diff options
Diffstat (limited to 'compiler')
63 files changed, 831 insertions, 536 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1827e42368f..a4ba1a5c9bf 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -236,7 +236,7 @@ enum ImplTraitContext { ReturnPositionOpaqueTy { /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, origin: hir::OpaqueTyOrigin, - in_trait: bool, + fn_kind: FnDeclKind, }, /// Impl trait in type aliases. TypeAliasesOpaqueTy { in_assoc_ty: bool }, @@ -312,7 +312,7 @@ impl std::fmt::Display for ImplTraitPosition { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum FnDeclKind { Fn, Inherent, @@ -1401,13 +1401,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, bounds) => { let span = t.span; match itctx { - ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self + ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self .lower_opaque_impl_trait( span, *origin, *def_node_id, bounds, - *in_trait, + Some(*fn_kind), itctx, ), &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self @@ -1416,7 +1416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OpaqueTyOrigin::TyAlias { in_assoc_ty }, *def_node_id, bounds, - false, + None, itctx, ), ImplTraitContext::Universal => { @@ -1523,7 +1523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, bounds: &GenericBounds, - in_trait: bool, + fn_kind: Option<FnDeclKind>, itctx: &ImplTraitContext, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. @@ -1540,10 +1540,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Vec::new() } hir::OpaqueTyOrigin::FnReturn(..) => { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` - // example, we only need to duplicate lifetimes that appear in the - // bounds, since those are the only ones that are captured by the opaque. - lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + if let FnDeclKind::Impl | FnDeclKind::Trait = + fn_kind.expect("expected RPITs to be lowered with a FnKind") + { + // return-position impl trait in trait was decided to capture all + // in-scope lifetimes, which we collect for all opaques during resolution. + self.resolver + .take_extra_lifetime_params(opaque_ty_node_id) + .into_iter() + .map(|(ident, id, _)| Lifetime { id, ident }) + .collect() + } else { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` + // example, we only need to duplicate lifetimes that appear in the + // bounds, since those are the only ones that are captured by the opaque. + lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + } } hir::OpaqueTyOrigin::AsyncFn(..) => { unreachable!("should be using `lower_async_fn_ret_ty`") @@ -1554,7 +1566,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_opaque_inner( opaque_ty_node_id, origin, - in_trait, + matches!(fn_kind, Some(FnDeclKind::Trait)), captured_lifetimes_to_duplicate, span, opaque_ty_span, @@ -1802,12 +1814,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let fn_def_id = self.local_def_id(fn_node_id); - self.lower_async_fn_ret_ty( - &decl.output, - fn_def_id, - ret_id, - matches!(kind, FnDeclKind::Trait), - ) + self.lower_async_fn_ret_ty(&decl.output, fn_def_id, ret_id, kind) } else { match &decl.output { FnRetTy::Ty(ty) => { @@ -1815,7 +1822,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - in_trait: matches!(kind, FnDeclKind::Trait), + fn_kind: kind, } } else { let position = match kind { @@ -1883,7 +1890,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { output: &FnRetTy, fn_def_id: LocalDefId, opaque_ty_node_id: NodeId, - in_trait: bool, + fn_kind: FnDeclKind, ) -> hir::FnRetTy<'hir> { let span = self.lower_span(output.span()); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); @@ -1898,7 +1905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, hir::OpaqueTyOrigin::AsyncFn(fn_def_id), - in_trait, + matches!(fn_kind, FnDeclKind::Trait), captured_lifetimes, span, opaque_ty_span, @@ -1906,7 +1913,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let future_bound = this.lower_async_fn_output_type_to_future_bound( output, span, - if in_trait && !this.tcx.features().return_position_impl_trait_in_trait { + if let FnDeclKind::Trait = fn_kind + && !this.tcx.features().return_position_impl_trait_in_trait + { ImplTraitContext::FeatureGated( ImplTraitPosition::TraitReturn, sym::return_position_impl_trait_in_trait, @@ -1914,7 +1923,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - in_trait, + fn_kind, } }, ); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 433da74231f..953d957a4ac 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -217,7 +217,7 @@ pub fn expand_include_bytes( }; match cx.source_map().load_binary_file(&file) { Ok(bytes) => { - let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes.into())); + let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); base::MacEager::expr(expr) } Err(e) => { diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index b7f56a2986c..5d775b9b532 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -39,7 +39,7 @@ fn clif_sig_from_fn_abi<'tcx>( pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { match c { Conv::Rust | Conv::C => default_call_conv, - Conv::RustCold => CallConv::Cold, + Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold, Conv::X86_64SysV => CallConv::SystemV, Conv::X86_64Win64 => CallConv::WindowsFastcall, diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 6fb1cbfad8c..377dc753f68 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -125,8 +125,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), PassMode::Pair(..) => { - argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true)); - argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true)); + argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0)); + argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1)); continue; } PassMode::Indirect { extra_attrs: Some(_), .. } => { diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 0b1f2fe6a87..308cb04cac3 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -821,7 +821,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let mut load = |i, scalar: &abi::Scalar, align| { let llptr = self.struct_gep(pair_type, place.llval, i as u64); - let llty = place.layout.scalar_pair_element_gcc_type(self, i, false); + let llty = place.layout.scalar_pair_element_gcc_type(self, i); let load = self.load(llty, llptr, align); scalar_load_metadata(self, load, scalar); if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index d1bfd833cd8..a81585d4128 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -55,7 +55,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>, - ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> { + ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> { // TODO(antoyo) None } diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 84d57838512..cc467801beb 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -4,7 +4,7 @@ use gccjit::{Struct, Type}; use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; @@ -74,8 +74,8 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout Abi::ScalarPair(..) => { return cx.type_struct( &[ - layout.scalar_pair_element_gcc_type(cx, 0, false), - layout.scalar_pair_element_gcc_type(cx, 1, false), + layout.scalar_pair_element_gcc_type(cx, 0), + layout.scalar_pair_element_gcc_type(cx, 1), ], false, ); @@ -150,7 +150,7 @@ pub trait LayoutGccExt<'tcx> { fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; - fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>; + fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc>; fn gcc_field_index(&self, index: usize) -> u64; fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>; } @@ -182,23 +182,16 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + // This must produce the same result for `repr(transparent)` wrappers as for the inner type! + // In other words, this should generally not look at the type at all, but only at the + // layout. if let Abi::Scalar(ref scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs // can be either fat or thin (data pointers of fat pointers). if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { return ty; } - let ty = - match *self.ty.kind() { - ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx)) - } - ty::Adt(def, _) if def.is_box() => { - cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx)) - } - ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())), - _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), - }; + let ty = self.scalar_gcc_type_at(cx, scalar, Size::ZERO); cx.scalar_types.borrow_mut().insert(self.ty, ty); return ty; } @@ -272,23 +265,10 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { } } - fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> { - // TODO(antoyo): remove llvm hack: - // HACK(eddyb) special-case fat pointers until LLVM removes - // pointee types, to avoid bitcasting every `OperandRef::deref`. - match self.ty.kind() { - ty::Ref(..) | ty::RawPtr(_) => { - return self.field(cx, index).gcc_type(cx); - } - // only wide pointer boxes are handled as pointers - // thin pointer boxes with scalar allocators are handled by the general logic below - ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_zst() => { - let ptr_ty = Ty::new_mut_ptr(cx.tcx,self.ty.boxed_ty()); - return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate); - } - _ => {} - } - + fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc> { + // This must produce the same result for `repr(transparent)` wrappers as for the inner type! + // In other words, this should generally not look at the type at all, but only at the + // layout. let (a, b) = match self.abi { Abi::ScalarPair(ref a, ref b) => (a, b), _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), @@ -367,8 +347,8 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { layout.gcc_field_index(index) } - fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> { - layout.scalar_pair_element_gcc_type(self, index, immediate) + fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, _immediate: bool) -> Type<'gcc> { + layout.scalar_pair_element_gcc_type(self, index) } fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> { diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index c6a7dc95d77..863cb7068f8 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -571,7 +571,9 @@ impl From<Conv> for llvm::CallConv { Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => { llvm::CCallConv } - Conv::RustCold => llvm::ColdCallConv, + Conv::Cold => llvm::ColdCallConv, + Conv::PreserveMost => llvm::PreserveMost, + Conv::PreserveAll => llvm::PreserveAll, Conv::AmdGpuKernel => llvm::AmdGpuKernel, Conv::AvrInterrupt => llvm::AvrInterrupt, Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 7a68c291aa5..d174a3593b9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -20,7 +20,7 @@ pub fn compute_mir_scopes<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, mir: &Body<'tcx>, - debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, + debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, ) { // Find all scopes with variables defined in them. let variables = if cx.sess().opts.debuginfo == DebugInfo::Full { @@ -51,7 +51,7 @@ fn make_mir_scope<'ll, 'tcx>( instance: Instance<'tcx>, mir: &Body<'tcx>, variables: &Option<BitSet<SourceScope>>, - debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, + debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, instantiated: &mut BitSet<SourceScope>, scope: SourceScope, ) { @@ -84,6 +84,7 @@ fn make_mir_scope<'ll, 'tcx>( } let loc = cx.lookup_debug_loc(scope_data.span.lo()); + let file_metadata = file_metadata(cx, &loc.file); let dbg_scope = match scope_data.inlined { Some((callee, _)) => { @@ -94,26 +95,18 @@ fn make_mir_scope<'ll, 'tcx>( ty::ParamEnv::reveal_all(), ty::EarlyBinder::bind(callee), ); - debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { - let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); - cx.dbg_scope_fn(callee, callee_fn_abi, None) - }) - } - None => { - let file_metadata = file_metadata(cx, &loc.file); - debug_context - .lexical_blocks - .entry((parent_scope.dbg_scope, loc.line, loc.col, file_metadata)) - .or_insert_with(|| unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope.dbg_scope, - file_metadata, - loc.line, - loc.col, - ) - }) + let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); + cx.dbg_scope_fn(callee, callee_fn_abi, None) } + None => unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlock( + DIB(cx), + parent_scope.dbg_scope, + file_metadata, + loc.line, + loc.col, + ) + }, }; let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 9cdeae2841b..40714a0afe9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -5,7 +5,7 @@ use rustc_codegen_ssa::mir::debuginfo::VariableKind::*; use self::metadata::{file_metadata, type_di_node}; use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER}; use self::namespace::mangled_name_of_instance; -use self::utils::{create_DIArray, debug_context, is_node_local_to_unit, DIB}; +use self::utils::{create_DIArray, is_node_local_to_unit, DIB}; use crate::abi::FnAbi; use crate::builder::Builder; @@ -67,8 +67,6 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> { type_map: metadata::TypeMap<'ll, 'tcx>, namespace_map: RefCell<DefIdMap<&'ll DIScope>>, recursion_marker_type: OnceCell<&'ll DIType>, - /// Maps a variable (name, scope, kind (argument or local), span) to its debug information. - variables: RefCell<FxHashMap<(Symbol, &'ll DIScope, VariableKind, Span), &'ll DIVariable>>, } impl Drop for CodegenUnitDebugContext<'_, '_> { @@ -93,7 +91,6 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { type_map: Default::default(), namespace_map: RefCell::new(Default::default()), recursion_marker_type: OnceCell::new(), - variables: RefCell::new(Default::default()), } } @@ -295,7 +292,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: &'ll Value, mir: &mir::Body<'tcx>, - ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> { + ) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> { if self.sess().opts.debuginfo == DebugInfo::None { return None; } @@ -307,11 +304,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { file_start_pos: BytePos(0), file_end_pos: BytePos(0), }; - let mut fn_debug_context = FunctionDebugContext { - scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes), - inlined_function_scopes: Default::default(), - lexical_blocks: Default::default(), - }; + let mut fn_debug_context = + FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) }; // Fill in all the scopes, with the information from the MIR body. compute_mir_scopes(self, instance, mir, &mut fn_debug_context); @@ -612,39 +606,33 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { variable_kind: VariableKind, span: Span, ) -> &'ll DIVariable { - debug_context(self) - .variables - .borrow_mut() - .entry((variable_name, scope_metadata, variable_kind, span)) - .or_insert_with(|| { - let loc = self.lookup_debug_loc(span.lo()); - let file_metadata = file_metadata(self, &loc.file); - - let type_metadata = type_di_node(self, variable_type); - - let (argument_index, dwarf_tag) = match variable_kind { - ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), - LocalVariable => (0, DW_TAG_auto_variable), - }; - let align = self.align_of(variable_type); - - let name = variable_name.as_str(); - unsafe { - llvm::LLVMRustDIBuilderCreateVariable( - DIB(self), - dwarf_tag, - scope_metadata, - name.as_ptr().cast(), - name.len(), - file_metadata, - loc.line, - type_metadata, - true, - DIFlags::FlagZero, - argument_index, - align.bytes() as u32, - ) - } - }) + let loc = self.lookup_debug_loc(span.lo()); + let file_metadata = file_metadata(self, &loc.file); + + let type_metadata = type_di_node(self, variable_type); + + let (argument_index, dwarf_tag) = match variable_kind { + ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), + LocalVariable => (0, DW_TAG_auto_variable), + }; + let align = self.align_of(variable_type); + + let name = variable_name.as_str(); + unsafe { + llvm::LLVMRustDIBuilderCreateVariable( + DIB(self), + dwarf_tag, + scope_metadata, + name.as_ptr().cast(), + name.len(), + file_metadata, + loc.line, + type_metadata, + true, + DIFlags::FlagZero, + argument_index, + align.bytes() as u32, + ) + } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 84157d1e25c..01cbf7d3b11 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -83,12 +83,17 @@ pub enum LLVMModFlagBehavior { // Consts for the LLVM CallConv type, pre-cast to usize. /// LLVM CallingConv::ID. Should we wrap this? +/// +/// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h> #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] pub enum CallConv { CCallConv = 0, FastCallConv = 8, ColdCallConv = 9, + PreserveMost = 14, + PreserveAll = 15, + Tail = 18, X86StdcallCallConv = 64, X86FastcallCallConv = 65, ArmAapcsCallConv = 67, diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 2be7bce115d..dcc62d314ff 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -3,7 +3,7 @@ use crate::context::TypeLowering; use crate::type_::Type; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_target::abi::HasDataLayout; @@ -215,20 +215,16 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { + // This must produce the same result for `repr(transparent)` wrappers as for the inner type! + // In other words, this should generally not look at the type at all, but only at the + // layout. if let Abi::Scalar(scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs // can be either fat or thin (data pointers of fat pointers). if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { return llty; } - let llty = match *self.ty.kind() { - ty::Ref(..) | ty::RawPtr(_) => cx.type_ptr(), - ty::Adt(def, _) if def.is_box() => cx.type_ptr(), - ty::FnPtr(sig) => { - cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) - } - _ => self.scalar_llvm_type_at(cx, scalar), - }; + let llty = self.scalar_llvm_type_at(cx, scalar); cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); return llty; } @@ -303,27 +299,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { index: usize, immediate: bool, ) -> &'a Type { - // HACK(eddyb) special-case fat pointers until LLVM removes - // pointee types, to avoid bitcasting every `OperandRef::deref`. - match *self.ty.kind() { - ty::Ref(..) | ty::RawPtr(_) => { - return self.field(cx, index).llvm_type(cx); - } - // only wide pointer boxes are handled as pointers - // thin pointer boxes with scalar allocators are handled by the general logic below - ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_zst() => { - let ptr_ty = Ty::new_mut_ptr(cx.tcx, self.ty.boxed_ty()); - return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); - } - // `dyn* Trait` has the same ABI as `*mut dyn Trait` - ty::Dynamic(bounds, region, ty::DynStar) => { - let ptr_ty = - Ty::new_mut_ptr(cx.tcx, Ty::new_dynamic(cx.tcx, bounds, region, ty::Dyn)); - return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); - } - _ => {} - } - + // This must produce the same result for `repr(transparent)` wrappers as for the inner type! + // In other words, this should generally not look at the type at all, but only at the + // layout. let Abi::ScalarPair(a, b) = self.abi else { bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self); }; @@ -405,7 +383,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Vectors, even for non-power-of-two sizes, have the same layout as // arrays but don't count as aggregate types + // While LLVM theoretically supports non-power-of-two sizes, and they + // often work fine, sometimes x86-isel deals with them horribly + // (see #115212) so for now only use power-of-two ones. if let FieldsShape::Array { count, .. } = self.layout.fields() + && count.is_power_of_two() && let element = self.field(cx, 0) && element.ty.is_integral() { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 7df830692d3..526c16a59de 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,12 +1,10 @@ use crate::traits::*; -use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::ty::Instance; use rustc_middle::ty::Ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; @@ -19,19 +17,11 @@ use super::{FunctionCx, LocalRef}; use std::ops::Range; -pub struct FunctionDebugContext<'tcx, S, L> { - /// Maps from source code to the corresponding debug info scope. +pub struct FunctionDebugContext<S, L> { pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, - - /// Maps from a given inlined function to its debug info declaration. - pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>, - - /// Maps from a lexical block (parent scope, line, column, file) to its debug info declaration. - /// This is particularily useful if the parent scope is an inlined function. - pub lexical_blocks: FxHashMap<(S, u32, u32, S), S>, } -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone)] pub enum VariableKind { ArgumentVariable(usize /*index*/), LocalVariable, @@ -445,9 +435,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.store(place.llval, alloca.llval, alloca.align); // Point the debug info to `*alloca` for the current variable - bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); + bx.dbg_var_addr( + dbg_var, + dbg_loc, + alloca.llval, + Size::ZERO, + &[Size::ZERO], + var.fragment, + ); } else { - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets, None); + bx.dbg_var_addr( + dbg_var, + dbg_loc, + base.llval, + direct_offset, + &indirect_offsets, + var.fragment, + ); } } @@ -570,17 +574,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let place = fragment.contents; + let fragment = if fragment_layout.size == Size::ZERO { + // Fragment is a ZST, so does not represent anything. + continue; + } else if fragment_layout.size == var_layout.size { + // Fragment covers entire variable, so as far as + // DWARF is concerned, it's not really a fragment. + None + } else { + Some(fragment_start..fragment_start + fragment_layout.size) + }; + per_local[place.local].push(PerLocalVarDebugInfo { name: var.name, source_info: var.source_info, dbg_var, - fragment: if fragment_layout.size == var_layout.size { - // Fragment covers entire variable, so as far as - // DWARF is concerned, it's not really a fragment. - None - } else { - Some(fragment_start..fragment_start + fragment_layout.size) - }, + fragment, projection: place.projection, }); } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 37a209cec5e..3d0c17e9cfb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -46,7 +46,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { mir: &'tcx mir::Body<'tcx>, - debug_context: Option<FunctionDebugContext<'tcx, Bx::DIScope, Bx::DILocation>>, + debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>, llfn: Bx::Function, diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 4acc0ea076c..63fecaf34fd 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -26,7 +26,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Function, mir: &mir::Body<'tcx>, - ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>>; + ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>; // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index ca7c484ea31..42a2fb0330c 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -255,6 +255,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, ) -> bool { + let primitive_abi_compat = |a1: abi::Primitive, a2: abi::Primitive| -> bool { + match (a1, a2) { + // For integers, ignore the sign. + (abi::Primitive::Int(int_ty1, _sign1), abi::Primitive::Int(int_ty2, _sign2)) => { + int_ty1 == int_ty2 + } + // For everything else we require full equality. + _ => a1 == a2, + } + }; // Heuristic for type comparison. let layout_compat = || { if caller_abi.layout.ty == callee_abi.layout.ty { @@ -267,28 +277,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // then who knows what happens. return false; } - if caller_abi.layout.size != callee_abi.layout.size - || caller_abi.layout.align.abi != callee_abi.layout.align.abi - { - // This cannot go well... - return false; - } - // The rest *should* be okay, but we are extra conservative. + // This is tricky. Some ABIs split aggregates up into multiple registers etc, so we have + // to be super careful here. For the scalar ABIs we conveniently already have all the + // newtypes unwrapped etc, so in those cases we can just compare the scalar components. + // Everything else we just reject for now. match (caller_abi.layout.abi, callee_abi.layout.abi) { - // Different valid ranges are okay (once we enforce validity, - // that will take care to make it UB to leave the range, just - // like for transmute). + // Different valid ranges are okay (the validity check will complain if this leads + // to invalid transmutes). (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => { - caller.primitive() == callee.primitive() + primitive_abi_compat(caller.primitive(), callee.primitive()) } ( abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(callee1, callee2), ) => { - caller1.primitive() == callee1.primitive() - && caller2.primitive() == callee2.primitive() + primitive_abi_compat(caller1.primitive(), callee1.primitive()) + && primitive_abi_compat(caller2.primitive(), callee2.primitive()) } - // Be conservative + // Be conservative. _ => false, } }; @@ -309,7 +315,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return true; }; let mode_compat = || match (&caller_abi.mode, &callee_abi.mode) { - (PassMode::Ignore, PassMode::Ignore) => true, + (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2), (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => { arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2) @@ -326,7 +332,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => false, }; + // We have to check both. `layout_compat` is needed to reject e.g. `i32` vs `f32`, + // which is not reflected in `PassMode`. `mode_compat` is needed to reject `u8` vs `bool`, + // which have the same `abi::Primitive` but different `arg_ext`. if layout_compat() && mode_compat() { + // Something went very wrong if our checks don't even imply that the layout is the same. + assert!( + caller_abi.layout.size == callee_abi.layout.size + && caller_abi.layout.align.abi == callee_abi.layout.align.abi + ); return true; } trace!( diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b829f24ab7a..770c3f7f02c 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -20,6 +20,8 @@ use rustc_mir_dataflow::{Analysis, ResultsCursor}; use rustc_target::abi::{Size, FIRST_VARIANT}; use rustc_target::spec::abi::Abi; +use crate::util::is_within_packed; + #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { Unwind, @@ -93,6 +95,7 @@ impl<'tcx> MirPass<'tcx> for Validator { cfg_checker.visit_body(body); cfg_checker.check_cleanup_control_flow(); + // Also run the TypeChecker. for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) { cfg_checker.fail(location, msg); } @@ -427,14 +430,34 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.check_unwind_edge(location, *unwind); // The call destination place and Operand::Move place used as an argument might be - // passed by a reference to the callee. Consequently they must be non-overlapping. - // Currently this simply checks for duplicate places. + // passed by a reference to the callee. Consequently they must be non-overlapping + // and cannot be packed. Currently this simply checks for duplicate places. self.place_cache.clear(); self.place_cache.insert(destination.as_ref()); + if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() { + // This is bad! The callee will expect the memory to be aligned. + self.fail( + location, + format!( + "encountered packed place in `Call` terminator destination: {:?}", + terminator.kind, + ), + ); + } let mut has_duplicates = false; for arg in args { if let Operand::Move(place) = arg { has_duplicates |= !self.place_cache.insert(place.as_ref()); + if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() { + // This is bad! The callee will expect the memory to be aligned. + self.fail( + location, + format!( + "encountered `Move` of a packed place in `Call` terminator: {:?}", + terminator.kind, + ), + ); + } } } @@ -442,7 +465,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.fail( location, format!( - "encountered overlapping memory in `Call` terminator: {:?}", + "encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}", terminator.kind, ), ); @@ -541,6 +564,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } } +/// A faster version of the validation pass that only checks those things which may break when apply +/// generic substitutions. pub fn validate_types<'tcx>( tcx: TyCtxt<'tcx>, mir_phase: MirPhase, diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index c1f0ff260d2..2e0643afb39 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -34,6 +34,7 @@ where false } _ => { + // We cannot figure out the layout. Conservatively assume that this is disaligned. debug!("is_disaligned({:?}) - true", place); true } diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 9ff401c3c7a..3910c6fa46d 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -20,7 +20,6 @@ //! the field `next_edge`). Each of those fields is an array that should //! be indexed by the direction (see the type `Direction`). -use crate::snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; use rustc_index::bit_set::BitSet; use std::fmt::Debug; @@ -28,8 +27,8 @@ use std::fmt::Debug; mod tests; pub struct Graph<N, E> { - nodes: SnapshotVec<Node<N>>, - edges: SnapshotVec<Edge<E>>, + nodes: Vec<Node<N>>, + edges: Vec<Edge<E>>, } pub struct Node<N> { @@ -45,20 +44,6 @@ pub struct Edge<E> { pub data: E, } -impl<N> SnapshotVecDelegate for Node<N> { - type Value = Node<N>; - type Undo = (); - - fn reverse(_: &mut Vec<Node<N>>, _: ()) {} -} - -impl<N> SnapshotVecDelegate for Edge<N> { - type Value = Edge<N>; - type Undo = (); - - fn reverse(_: &mut Vec<Edge<N>>, _: ()) {} -} - #[derive(Copy, Clone, PartialEq, Debug)] pub struct NodeIndex(pub usize); @@ -86,11 +71,11 @@ impl NodeIndex { impl<N: Debug, E: Debug> Graph<N, E> { pub fn new() -> Graph<N, E> { - Graph { nodes: SnapshotVec::new(), edges: SnapshotVec::new() } + Graph { nodes: Vec::new(), edges: Vec::new() } } pub fn with_capacity(nodes: usize, edges: usize) -> Graph<N, E> { - Graph { nodes: SnapshotVec::with_capacity(nodes), edges: SnapshotVec::with_capacity(edges) } + Graph { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } } // # Simple accessors diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index d104ff0891d..2daf591bd65 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -516,7 +516,8 @@ E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), } -// Undocumented removed error codes. Note that many removed error codes are documented. +// Undocumented removed error codes. Note that many removed error codes are kept in the list above +// and marked as no-longer emitted with a note in the markdown file (see E0001 for an example). // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard // E0019, // merged into E0015 diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 2f7cff3ce5c..e745ef1ec07 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -813,7 +813,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), + rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), rustc_attr!( TEST, rustc_error, Normal, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7b9f61d7ab2..334e0541c76 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -56,6 +56,7 @@ pub fn provide(providers: &mut Providers) { resolve_bound_vars::provide(providers); *providers = Providers { type_of: type_of::type_of, + type_of_opaque: type_of::type_of_opaque, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, generics_of: generics_of::generics_of, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 2bbdbe3a1f6..d12337687e2 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -1,7 +1,8 @@ use rustc_errors::{Applicability, StashKey}; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::HirId; +use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; @@ -388,86 +389,62 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } }, - Node::Item(item) => { - match item.kind { - ItemKind::Static(ty, .., body_id) => { - if is_suggestable_infer_ty(ty) { - infer_placeholder_type( - tcx, - def_id, - body_id, - ty.span, - item.ident, - "static variable", - ) - } else { - icx.to_ty(ty) - } - } - ItemKind::Const(ty, _, body_id) => { - if is_suggestable_infer_ty(ty) { - infer_placeholder_type( - tcx, def_id, body_id, ty.span, item.ident, "constant", - ) - } else { - icx.to_ty(ty) - } - } - ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty), - ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() { - spans if spans.len() > 0 => { - let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf { - span: spans.into(), - note: (), - }); - Ty::new_error(tcx, guar) - } - _ => icx.to_ty(*self_ty), - }, - ItemKind::Fn(..) => { - let args = ty::GenericArgs::identity_for_item(tcx, def_id); - Ty::new_fn_def(tcx, def_id.to_def_id(), args) - } - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { - let def = tcx.adt_def(def_id); - let args = ty::GenericArgs::identity_for_item(tcx, def_id); - Ty::new_adt(tcx, def, args) + Node::Item(item) => match item.kind { + ItemKind::Static(ty, .., body_id) => { + if is_suggestable_infer_ty(ty) { + infer_placeholder_type( + tcx, + def_id, + body_id, + ty.span, + item.ident, + "static variable", + ) + } else { + icx.to_ty(ty) } - ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { .. }, - .. - }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), - // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(&OpaqueTy { - origin: - hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), - in_trait, - .. - }) => { - if in_trait && !tcx.defaultness(owner).has_value() { - span_bug!( - tcx.def_span(def_id), - "tried to get type of this RPITIT with no definition" - ); - } - opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) + } + ItemKind::Const(ty, _, body_id) => { + if is_suggestable_infer_ty(ty) { + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") + } else { + icx.to_ty(ty) } - ItemKind::Trait(..) - | ItemKind::TraitAlias(..) - | ItemKind::Macro(..) - | ItemKind::Mod(..) - | ItemKind::ForeignMod { .. } - | ItemKind::GlobalAsm(..) - | ItemKind::ExternCrate(..) - | ItemKind::Use(..) => { - span_bug!( - item.span, - "compute_type_of_item: unexpected item type: {:?}", - item.kind - ); + } + ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty), + ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() { + spans if spans.len() > 0 => { + let guar = tcx + .sess + .emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () }); + Ty::new_error(tcx, guar) } + _ => icx.to_ty(*self_ty), + }, + ItemKind::Fn(..) => { + let args = ty::GenericArgs::identity_for_item(tcx, def_id); + Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - } + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { + let def = tcx.adt_def(def_id); + let args = ty::GenericArgs::identity_for_item(tcx, def_id); + Ty::new_adt(tcx, def, args) + } + ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else( + |CyclePlaceholder(guar)| Ty::new_error(tcx, guar), + |ty| ty.instantiate_identity(), + ), + ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + | ItemKind::Macro(..) + | ItemKind::Mod(..) + | ItemKind::ForeignMod { .. } + | ItemKind::GlobalAsm(..) + | ItemKind::ExternCrate(..) + | ItemKind::Use(..) => { + span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind); + } + }, Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { @@ -514,6 +491,51 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty ty::EarlyBinder::bind(output) } +pub(super) fn type_of_opaque( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> { + if let Some(def_id) = def_id.as_local() { + use rustc_hir::*; + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + Ok(ty::EarlyBinder::bind(match tcx.hir().get(hir_id) { + Node::Item(item) => match item.kind { + ItemKind::OpaqueTy(OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. + }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), + // Opaque types desugared from `impl Trait`. + ItemKind::OpaqueTy(&OpaqueTy { + origin: + hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), + in_trait, + .. + }) => { + if in_trait && !tcx.defaultness(owner).has_value() { + span_bug!( + tcx.def_span(def_id), + "tried to get type of this RPITIT with no definition" + ); + } + opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) + } + _ => { + span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind); + } + }, + + x => { + bug!("unexpected sort of node in type_of_opaque(): {:?}", x); + } + })) + } else { + // Foreign opaque type will go through the foreign provider + // and load the type from metadata. + Ok(tcx.type_of(def_id)) + } +} + fn infer_placeholder_type<'a>( tcx: TyCtxt<'a>, def_id: LocalDefId, diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index d57d05d7605..d98dc0e6b83 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -1,9 +1,24 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; use crate::errors; pub fn test_variance(tcx: TyCtxt<'_>) { + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { + let variances_of = tcx.variances_of(id.owner_id); + + tcx.sess.emit_err(errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances_of: format!("{variances_of:?}"), + }); + } + } + } + // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. for id in tcx.hir().items() { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index b19fb6da6de..e426b937542 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let inferred_sig = self.normalize( span, self.deduce_sig_from_projection( - Some(span), + Some(span), bound_predicate.rebind(proj_predicate), ), ); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index f6a5b8f97a1..2acb43c51da 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -20,10 +20,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else { return false; }; - let hir = self.tcx.hir(); - let hir::Node::Expr(expr) = hir.get(hir_id) else { - return false; - }; let Some(unsubstituted_pred) = self .tcx @@ -47,6 +43,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return false, }; + let direct_param = if let ty::ClauseKind::Trait(pred) = unsubstituted_pred.kind().skip_binder() + && let ty = pred.trait_ref.self_ty() + && let ty::Param(_param) = ty.kind() + && let Some(arg) = predicate_args.get(0) + && let ty::GenericArgKind::Type(arg_ty) = arg.unpack() + && arg_ty == ty + { + Some(*arg) + } else { + None + }; let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| { predicate_args.iter().find_map(|arg| { arg.walk().find_map(|arg| { @@ -96,54 +103,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); } - if self.closure_span_overlaps_error(error, expr.span) { - return false; - } + let hir = self.tcx.hir(); + let (expr, qpath) = match hir.get(hir_id) { + hir::Node::Expr(expr) => { + if self.closure_span_overlaps_error(error, expr.span) { + return false; + } + let qpath = + if let hir::ExprKind::Path(qpath) = expr.kind { Some(qpath) } else { None }; - match &expr.kind { - hir::ExprKind::Path(qpath) => { - if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Call(callee, args), - hir_id: call_hir_id, - span: call_span, - .. - }) = hir.get_parent(expr.hir_id) - && callee.hir_id == expr.hir_id - { - if self.closure_span_overlaps_error(error, *call_span) { - return false; - } + (Some(*expr), qpath) + } + hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => (None, Some(*qpath)), + _ => return false, + }; - for param in - [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] - .into_iter() - .flatten() - { - if self.blame_specific_arg_if_possible( - error, - def_id, - param, - *call_hir_id, - callee.span, - None, - args, - ) - { - return true; - } - } + if let Some(qpath) = qpath { + if let Some(param) = direct_param { + if self.point_at_path_if_possible(error, def_id, param, &qpath) { + return true; + } + } + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Call(callee, args), + hir_id: call_hir_id, + span: call_span, + .. + }) = hir.get_parent(hir_id) + && callee.hir_id == hir_id + { + if self.closure_span_overlaps_error(error, *call_span) { + return false; } - for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + for param in + [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] .into_iter() .flatten() { - if self.point_at_path_if_possible(error, def_id, param, qpath) { + if self.blame_specific_arg_if_possible( + error, + def_id, + param, + *call_hir_id, + callee.span, + None, + args, + ) + { return true; } } } - hir::ExprKind::MethodCall(segment, receiver, args, ..) => { + + for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + .into_iter() + .flatten() + { + if self.point_at_path_if_possible(error, def_id, param, &qpath) { + return true; + } + } + } + + match expr.map(|e| e.kind) { + Some(hir::ExprKind::MethodCall(segment, receiver, args, ..)) => { + if let Some(param) = direct_param + && self.point_at_generic_if_possible(error, def_id, param, segment) + { + error.obligation.cause.map_code(|parent_code| { + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id: receiver.hir_id, + call_hir_id: hir_id, + parent_code, + } + }); + return true; + } for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] .into_iter() .flatten() @@ -175,7 +211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } } - hir::ExprKind::Struct(qpath, fields, ..) => { + Some(hir::ExprKind::Struct(qpath, fields, ..)) => { if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) = self.typeck_results.borrow().qpath_res(qpath, hir_id) { @@ -200,9 +236,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] - .into_iter() - .flatten() + for param in [ + direct_param, + param_to_point_at, + fallback_param_to_point_at, + self_param_to_point_at, + ] + .into_iter() + .flatten() { if self.point_at_path_if_possible(error, def_id, param, qpath) { return true; @@ -434,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /** - * Recursively searches for the most-specific blamable expression. + * Recursively searches for the most-specific blameable expression. * For example, if you have a chain of constraints like: * - want `Vec<i32>: Copy` * - because `Option<Vec<i32>>: Copy` needs `Vec<i32>: Copy` because `impl <T: Copy> Copy for Option<T>` diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 6a82b00211e..7707cc6de54 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -317,7 +317,18 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) { // FIXME: normalization and escaping regions - let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; + let ty = if !ty.has_escaping_bound_vars() { + if let ty::Alias( + ty::AliasKind::Projection | ty::AliasKind::Weak, + ty::AliasTy { args, def_id, .. }, + ) = ty.kind() + { + self.add_required_obligations_for_hir(span, *def_id, args, hir_id); + } + self.normalize(span, ty) + } else { + ty + }; self.write_ty(hir_id, ty) } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 60d9d6578f5..cb651363982 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -15,7 +15,6 @@ use rustc_data_structures::graph::implementation::{ use rustc_data_structures::intern::Interned; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::PlaceholderRegion; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReEarlyBound, ReErased, ReError, ReFree, ReStatic}; use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar}; @@ -173,38 +172,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } - /// Gets the LUb of a given region and the empty region - fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> { - match *a_region { - ReLateBound(..) | ReErased => { - bug!("cannot relate region: {:?}", a_region); - } - - ReVar(v_id) => { - span_bug!( - self.var_infos[v_id].origin.span(), - "lub invoked with non-concrete regions: {:?}", - a_region, - ); - } - - ReStatic => { - // nothing lives longer than `'static` - Ok(self.tcx().lifetimes.re_static) - } - - ReError(_) => Ok(a_region), - - ReEarlyBound(_) | ReFree(_) => { - // All empty regions are less than early-bound, free, - // and scope regions. - Ok(a_region) - } - - RePlaceholder(placeholder) => Err(placeholder), - } - } - fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { // In the first pass, we expand region vids according to constraints we // have previously found. In the second pass, we loop through the region @@ -247,27 +214,25 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { true } VarValue::Value(cur_region) => { - let lub = match self.lub_empty(cur_region) { - Ok(r) => r, - // If the empty and placeholder regions are in the same universe, - // then the LUB is the Placeholder region (which is the cur_region). - // If they are not in the same universe, the LUB is the Static lifetime. - Err(placeholder) if a_universe == placeholder.universe => { - cur_region + match *cur_region { + // If this empty region is from a universe that can name the + // placeholder universe, then the LUB is the Placeholder region + // (which is the cur_region). Otherwise, the LUB is the Static + // lifetime. + RePlaceholder(placeholder) + if !a_universe.can_name(placeholder.universe) => + { + let lub = self.tcx().lifetimes.re_static; + debug!( + "Expanding value of {:?} from {:?} to {:?}", + b_vid, cur_region, lub + ); + + *b_data = VarValue::Value(lub); + true } - Err(_) => self.tcx().lifetimes.re_static, - }; - - if lub == cur_region { - false - } else { - debug!( - "Expanding value of {:?} from {:?} to {:?}", - b_vid, cur_region, lub - ); - - *b_data = VarValue::Value(lub); - true + + _ => false, } } @@ -341,15 +306,19 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { match *b_data { VarValue::Empty(empty_ui) => { - let lub = match self.lub_empty(a_region) { - Ok(r) => r, - // If this empty region is from a universe that can - // name the placeholder, then the placeholder is - // larger; otherwise, the only ancestor is `'static`. - Err(placeholder) if empty_ui.can_name(placeholder.universe) => { - ty::Region::new_placeholder(self.tcx(), placeholder) + let lub = match *a_region { + RePlaceholder(placeholder) => { + // If this empty region is from a universe that can + // name the placeholder, then the placeholder is + // larger; otherwise, the only ancestor is `'static`. + if empty_ui.can_name(placeholder.universe) { + ty::Region::new_placeholder(self.tcx(), placeholder) + } else { + self.tcx().lifetimes.re_static + } } - Err(_) => self.tcx().lifetimes.re_static, + + _ => a_region, }; debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 18a669175b9..f6cbbad6338 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -22,7 +22,7 @@ use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; -use rustc_passes::{self, hir_stats, layout_test}; +use rustc_passes::{self, abi_test, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; @@ -818,6 +818,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } sess.time("layout_testing", || layout_test::test_layout(tcx)); + sess.time("abi_testing", || abi_test::test_abi(tcx)); // Avoid overwhelming user with errors if borrow checking failed. // I'm not sure how helpful this is, to be honest, but it avoids a diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index db669ca7250..b53ba251bcd 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -807,6 +807,7 @@ fn test_unstable_options_tracking_hash() { tracked!(no_jump_tables, true); tracked!(no_link, true); tracked!(no_profiler_runtime, true); + tracked!(no_trait_vptr, true); tracked!(no_unique_section_names, true); tracked!(oom, OomStrategy::Panic); tracked!(osx_rpath_install_name, true); @@ -821,7 +822,7 @@ fn test_unstable_options_tracking_hash() { tracked!(profile_emit, Some(PathBuf::from("abc"))); tracked!(profile_sample_use, Some(PathBuf::from("abc"))); tracked!(profiler_runtime, "abc".to_string()); - tracked!(relax_elf_relocations, Some(false)); + tracked!(relax_elf_relocations, Some(true)); tracked!(relro_level, Some(RelroLevel::Full)); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(report_delayed_bugs, true); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index b566ea496de..6af5c24c458 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -321,13 +321,13 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, PrintBackendInfo Print, void* Out) { const TargetMachine *Target = unwrap(TM); - const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch(); const Triple::ArchType TargetArch = Target->getTargetTriple().getArch(); std::ostringstream Buf; #if LLVM_VERSION_GE(17, 0) + const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions(); #else Buf << "Full target CPU help is not supported by this LLVM version.\n\n"; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index be91ad4088a..5ade67c62ff 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -347,6 +347,13 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Symbol { } } +impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for [u8] { + fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) { + Encoder::emit_usize(e, self.len()); + e.emit_raw_bytes(self); + } +} + impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = true; diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 348f79ed6a8..9b666222ad0 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -1,4 +1,5 @@ use crate::mir; +use crate::query::CyclePlaceholder; use crate::traits; use crate::ty::{self, Ty}; use std::mem::{size_of, transmute_copy, MaybeUninit}; @@ -142,6 +143,10 @@ impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> { [u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()]; } +impl EraseType for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> { + type Result = [u8; size_of::<Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder>>()]; +} + impl<T> EraseType for Option<&'_ T> { type Result = [u8; size_of::<Option<&'static ()>>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 94ae0dcb517..bf340846f10 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -26,7 +26,7 @@ use crate::mir::interpret::{ use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::query::erase::{erase, restore, Erase}; -use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery}; +use crate::query::plumbing::{query_ensure, query_get_at, CyclePlaceholder, DynamicQuery}; use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, @@ -243,6 +243,16 @@ rustc_queries! { feedable } + /// Specialized instance of `type_of` that detects cycles that are due to + /// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs + /// to be handled separately, call `type_of` instead. + query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<Ty<'tcx>>, CyclePlaceholder> { + desc { |tcx| + "computing type of opaque `{path}`", + path = tcx.def_path_str(key), + } + } + query collect_return_position_impl_trait_in_trait_tys(key: DefId) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index a1aac284621..a342b5231e9 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -19,7 +19,7 @@ use rustc_query_system::dep_graph::SerializedDepNodeIndex; pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; use rustc_query_system::HandleCycleError; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; use std::ops::Deref; pub struct QueryKeyStringCache { @@ -52,7 +52,8 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { pub loadable_from_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, pub hash_result: HashResult<C::Value>, - pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value, + pub value_from_cycle_error: + fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>], guar: ErrorGuaranteed) -> C::Value, pub format_value: fn(&C::Value) -> String, } @@ -629,3 +630,6 @@ impl<'tcx> TyCtxtAt<'tcx> { .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) } } + +#[derive(Copy, Clone, Debug, HashStable)] +pub struct CyclePlaceholder(pub ErrorGuaranteed); diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 384a368434a..962faf56cb8 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -1,4 +1,5 @@ use crate::dep_graph::DepKind; +use crate::query::plumbing::CyclePlaceholder; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_hir as hir; @@ -8,20 +9,38 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::query::QueryInfo; use rustc_query_system::Value; use rustc_span::def_id::LocalDefId; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use std::fmt::Write; impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + _: &[QueryInfo<DepKind>], + guar: ErrorGuaranteed, + ) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. - unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) } + unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) } + } +} + +impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> { + fn from_cycle_error( + _tcx: TyCtxt<'tcx>, + _: &[QueryInfo<DepKind>], + guar: ErrorGuaranteed, + ) -> Self { + Err(CyclePlaceholder(guar)) } } impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + _: &[QueryInfo<DepKind>], + _guar: ErrorGuaranteed, + ) -> Self { // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -33,8 +52,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> { } impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self { - let err = Ty::new_misc_error(tcx); + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + stack: &[QueryInfo<DepKind>], + guar: ErrorGuaranteed, + ) -> Self { + let err = Ty::new_error(tcx, guar); let arity = if let Some(frame) = stack.get(0) && frame.query.dep_kind == DepKind::fn_sig @@ -63,7 +86,11 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { } impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle: &[QueryInfo<DepKind>], + _guar: ErrorGuaranteed, + ) -> Self { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); for info in cycle { @@ -95,22 +122,35 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { } impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { - ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle)) + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle: &[QueryInfo<DepKind>], + guar: ErrorGuaranteed, + ) -> Self { + ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar)) } } impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { - ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle)) + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle: &[QueryInfo<DepKind>], + guar: ErrorGuaranteed, + ) -> Self { + ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar)) } } impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> { - fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self { + fn from_cycle_error( + _tcx: TyCtxt<'tcx>, + _cycle: &[QueryInfo<DepKind>], + _guar: ErrorGuaranteed, + ) -> Self { // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // tcx.arena.alloc is pretty much equal to leaking). + // FIXME: `Cycle` should carry the ErrorGuaranteed Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle))) } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f917e52109a..bf88360a8c1 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -590,6 +590,8 @@ struct MirUsedCollector<'a, 'tcx> { body: &'a mir::Body<'tcx>, output: &'a mut MonoItems<'tcx>, instance: Instance<'tcx>, + /// Spans for move size lints already emitted. Helps avoid duplicate lints. + move_size_spans: Vec<Span>, } impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { @@ -604,6 +606,45 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { ty::EarlyBinder::bind(value), ) } + + fn check_move_size(&mut self, limit: usize, operand: &mir::Operand<'tcx>, location: Location) { + let limit = Size::from_bytes(limit); + let ty = operand.ty(self.body, self.tcx); + let ty = self.monomorphize(ty); + let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { return }; + if layout.size <= limit { + return; + } + debug!(?layout); + let source_info = self.body.source_info(location); + debug!(?source_info); + for span in &self.move_size_spans { + if span.overlaps(source_info.span) { + return; + } + } + let lint_root = source_info.scope.lint_root(&self.body.source_scopes); + debug!(?lint_root); + let Some(lint_root) = lint_root else { + // This happens when the issue is in a function from a foreign crate that + // we monomorphized in the current crate. We can't get a `HirId` for things + // in other crates. + // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root + // but correct span? This would make the lint at least accept crate-level lint attributes. + return; + }; + self.tcx.emit_spanned_lint( + LARGE_ASSIGNMENTS, + lint_root, + source_info.span, + LargeAssignmentsLint { + span: source_info.span, + size: layout.size.bytes(), + limit: limit.bytes(), + }, + ); + self.move_size_spans.push(source_info.span); + } } impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { @@ -803,40 +844,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { self.super_operand(operand, location); - let limit = self.tcx.move_size_limit().0; - if limit == 0 { - return; - } - let limit = Size::from_bytes(limit); - let ty = operand.ty(self.body, self.tcx); - let ty = self.monomorphize(ty); - let layout = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)); - if let Ok(layout) = layout { - if layout.size > limit { - debug!(?layout); - let source_info = self.body.source_info(location); - debug!(?source_info); - let lint_root = source_info.scope.lint_root(&self.body.source_scopes); - debug!(?lint_root); - let Some(lint_root) = lint_root else { - // This happens when the issue is in a function from a foreign crate that - // we monomorphized in the current crate. We can't get a `HirId` for things - // in other crates. - // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root - // but correct span? This would make the lint at least accept crate-level lint attributes. - return; - }; - self.tcx.emit_spanned_lint( - LARGE_ASSIGNMENTS, - lint_root, - source_info.span, - LargeAssignmentsLint { - span: source_info.span, - size: layout.size.bytes(), - limit: limit.bytes(), - }, - ) - } + let move_size_limit = self.tcx.move_size_limit().0; + if move_size_limit > 0 { + self.check_move_size(move_size_limit, operand, location); } } @@ -1363,7 +1373,8 @@ fn collect_used_items<'tcx>( output: &mut MonoItems<'tcx>, ) { let body = tcx.instance_mir(instance.def); - MirUsedCollector { tcx, body: &body, output, instance }.visit_body(&body); + MirUsedCollector { tcx, body: &body, output, instance, move_size_spans: vec![] } + .visit_body(&body); } #[instrument(skip(tcx, output), level = "debug")] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index b2a4da885aa..57598cf8bcf 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -7,6 +7,9 @@ passes_abi = abi: {$abi} +passes_abi_of = + fn_abi_of_instance({$fn_name}) = {$fn_abi} + passes_align = align: {$align} diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs new file mode 100644 index 00000000000..5c0438e78ae --- /dev/null +++ b/compiler/rustc_passes/src/abi_test.rs @@ -0,0 +1,93 @@ +use rustc_ast::Attribute; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::layout::{FnAbiError, LayoutError}; +use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt}; +use rustc_span::source_map::Spanned; +use rustc_span::symbol::sym; + +use crate::errors::{AbiOf, UnrecognizedField}; + +pub fn test_abi(tcx: TyCtxt<'_>) { + if !tcx.features().rustc_attrs { + // if the `rustc_attrs` feature is not enabled, don't bother testing ABI + return; + } + for id in tcx.hir().items() { + match tcx.def_kind(id.owner_id) { + DefKind::Fn => { + for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { + dump_abi_of(tcx, id.owner_id.def_id.into(), attr); + } + } + DefKind::Impl { .. } => { + // To find associated functions we need to go into the child items here. + for &id in tcx.associated_item_def_ids(id.owner_id) { + if matches!(tcx.def_kind(id), DefKind::AssocFn) { + for attr in tcx.get_attrs(id, sym::rustc_abi) { + dump_abi_of(tcx, id, attr); + } + } + } + } + _ => {} + } + } +} + +fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { + let param_env = tcx.param_env(item_def_id); + let args = GenericArgs::identity_for_item(tcx, item_def_id); + let instance = match Instance::resolve(tcx, param_env, item_def_id, args) { + Ok(Some(instance)) => instance, + Ok(None) => { + // Not sure what to do here, but `LayoutError::Unknown` seems reasonable? + let ty = tcx.type_of(item_def_id).instantiate_identity(); + tcx.sess.emit_fatal(Spanned { + node: LayoutError::Unknown(ty).into_diagnostic(), + + span: tcx.def_span(item_def_id), + }); + } + Err(_guaranteed) => return, + }; + match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) { + Ok(abi) => { + // Check out the `#[rustc_abi(..)]` attribute to tell what to dump. + // The `..` are the names of fields to dump. + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::debug => { + let fn_name = tcx.item_name(item_def_id); + tcx.sess.emit_err(AbiOf { + span: tcx.def_span(item_def_id), + fn_name, + fn_abi: format!("{:#?}", abi), + }); + } + + name => { + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); + } + } + } + } + + Err(FnAbiError::Layout(layout_error)) => { + tcx.sess.emit_fatal(Spanned { + node: layout_error.into_diagnostic(), + span: tcx.def_span(item_def_id), + }); + } + Err(FnAbiError::AdjustForForeignAbi(e)) => { + // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if + // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE + // isn't the worst thing. Also this matches what codegen does. + span_bug!( + tcx.def_span(item_def_id), + "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", + ) + } + } +} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 683717344ce..32dd02a4aa9 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -914,6 +914,15 @@ pub struct LayoutOf { } #[derive(Diagnostic)] +#[diag(passes_abi_of)] +pub struct AbiOf { + #[primary_span] + pub span: Span, + pub fn_name: Symbol, + pub fn_abi: String, +} + +#[derive(Diagnostic)] #[diag(passes_unrecognized_field)] pub struct UnrecognizedField { #[primary_span] diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index a7a8af864ac..d839fee07a6 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -11,16 +11,17 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout}; use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField}; pub fn test_layout(tcx: TyCtxt<'_>) { - if tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout - for id in tcx.hir().items() { - if matches!( - tcx.def_kind(id.owner_id), - DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union - ) { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { - dump_layout_of(tcx, id.owner_id.def_id, attr); - } + return; + } + for id in tcx.hir().items() { + if matches!( + tcx.def_kind(id.owner_id), + DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union + ) { + for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { + dump_layout_of(tcx, id.owner_id.def_id, attr); } } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 0da4b294648..51f3c9ad76f 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -24,6 +24,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_middle::query::Providers; +pub mod abi_test; mod check_attr; mod check_const; pub mod dead; diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 775870106b1..9a0fcbb37a7 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -41,7 +41,7 @@ use rustc_query_system::query::{ }; use rustc_query_system::HandleCycleError; use rustc_query_system::Value; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; #[macro_use] mod plumbing; @@ -146,8 +146,9 @@ where self, tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>], + guar: ErrorGuaranteed, ) -> Self::Value { - (self.dynamic.value_from_cycle_error)(tcx, cycle) + (self.dynamic.value_from_cycle_error)(tcx, cycle, guar) } #[inline(always)] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index def6ac280b8..a30ea7c1ddc 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -605,8 +605,8 @@ macro_rules! define_queries { } { |_tcx, _key, _prev_index, _index| None }), - value_from_cycle_error: |tcx, cycle| { - let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle); + value_from_cycle_error: |tcx, cycle, guar| { + let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle, guar); erase(result) }, loadable_from_disk: |_tcx, _key, _index| { diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 7e47d701205..d14c6315dc1 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -8,6 +8,7 @@ use crate::query::DepNodeIndex; use crate::query::{QueryContext, QueryInfo, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_span::ErrorGuaranteed; use std::fmt::Debug; use std::hash::Hash; @@ -57,6 +58,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { self, tcx: Qcx::DepContext, cycle: &[QueryInfo<Qcx::DepKind>], + guar: ErrorGuaranteed, ) -> Self::Value; fn anon(self) -> bool; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 4adb4eb7475..85c9b727308 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -148,8 +148,8 @@ where use HandleCycleError::*; match query.handle_cycle_error() { Error => { - error.emit(); - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) + let guar = error.emit(); + query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) } Fatal => { error.emit(); @@ -157,8 +157,8 @@ where unreachable!() } DelayBug => { - error.delay_as_bug(); - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) + let guar = error.delay_as_bug(); + query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) } } } @@ -300,7 +300,18 @@ where match result { Ok(()) => { let Some((v, index)) = query.query_cache(qcx).lookup(&key) else { - cold_path(|| panic!("value must be in cache after waiting")) + cold_path(|| { + // We didn't find the query result in the query cache. Check if it was + // poisoned due to a panic instead. + let lock = query.query_state(qcx).active.get_shard_by_value(&key).lock(); + match lock.get(&key) { + // The query we waited on panicked. Continue unwinding here. + Some(QueryResult::Poisoned) => FatalError.raise(), + _ => panic!( + "query result must in the cache or the query must be poisoned after a wait" + ), + } + }) }; qcx.dep_context().profiler().query_cache_hit(index.into()); diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs index ce551078cc0..07c28fdb73b 100644 --- a/compiler/rustc_query_system/src/values.rs +++ b/compiler/rustc_query_system/src/values.rs @@ -1,12 +1,14 @@ +use rustc_span::ErrorGuaranteed; + use crate::dep_graph::{DepContext, DepKind}; use crate::query::QueryInfo; pub trait Value<Tcx: DepContext, D: DepKind>: Sized { - fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> Self; + fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], guar: ErrorGuaranteed) -> Self; } impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T { - default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> T { + default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], _guar: ErrorGuaranteed) -> T { tcx.sess().abort_if_errors(); // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's // non-trivial to define it earlier. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 22d084c8e0b..500004269c9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -772,9 +772,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(..) => { + TyKind::ImplTrait(node_id, _) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); + self.record_lifetime_params_for_impl_trait(*node_id); self.lifetime_elision_candidates = candidates; } TyKind::TraitObject(bounds, ..) => { @@ -909,8 +910,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, &sig.decl.output, ); - if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() { - this.record_lifetime_params_for_impl_trait(async_node_id, span); + if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() { + this.record_lifetime_params_for_impl_trait(async_node_id); } }, ); @@ -951,8 +952,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, &declaration.output, ); - if let Some((async_node_id, span)) = async_node_id { - this.record_lifetime_params_for_impl_trait(async_node_id, span); + if let Some((async_node_id, _)) = async_node_id { + this.record_lifetime_params_for_impl_trait(async_node_id); } }, ); @@ -4367,7 +4368,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// We include all lifetime parameters, either named or "Fresh". /// The order of those parameters does not matter, as long as it is /// deterministic. - fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) { + fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) { let mut extra_lifetime_params = vec![]; for rib in self.lifetime_ribs.iter().rev() { @@ -4380,14 +4381,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { extra_lifetime_params.extend(earlier_fresh); } } - LifetimeRibKind::Generics { .. } => {} - _ => { - // We are in a function definition. We should only find `Generics` - // and `AnonymousCreateParameter` inside the innermost `Item`. - span_bug!(span, "unexpected rib kind: {:?}", rib.kind) - } + _ => {} } } + self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 055ab2d9c15..40099de707b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1631,6 +1631,8 @@ options! { "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED], "prevent automatic injection of the profiler_builtins crate"), + no_trait_vptr: bool = (false, parse_no_flag, [TRACKED], + "disable generation of trait vptr in vtable for upcasting"), no_unique_section_names: bool = (false, parse_bool, [TRACKED], "do not use unique names for text and data sections when -Z function-sections is used"), normalize_docs: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index efaed0f68ce..62fe49fe2a2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -21,6 +21,8 @@ #![feature(rustc_attrs)] #![feature(let_chains)] #![feature(round_char_boundary)] +#![feature(read_buf)] +#![feature(new_uninit)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 983b2ab04a4..1cff021ba41 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -24,6 +24,8 @@ use std::sync::atomic::Ordering; use std::fs; use std::io; +use std::io::BorrowedBuf; +use std::io::Read; #[cfg(test)] mod tests; @@ -101,10 +103,13 @@ pub trait FileLoader { fn file_exists(&self, path: &Path) -> bool; /// Read the contents of a UTF-8 file into memory. + /// This function must return a String because we normalize + /// source files, which may require resizing. fn read_file(&self, path: &Path) -> io::Result<String>; /// Read the contents of a potentially non-UTF-8 file into memory. - fn read_binary_file(&self, path: &Path) -> io::Result<Vec<u8>>; + /// We don't normalize binary files, so we can start in an Lrc. + fn read_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>>; } /// A FileLoader that uses std::fs to load real files. @@ -119,8 +124,16 @@ impl FileLoader for RealFileLoader { fs::read_to_string(path) } - fn read_binary_file(&self, path: &Path) -> io::Result<Vec<u8>> { - fs::read(path) + fn read_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>> { + let mut file = fs::File::open(path)?; + let len = file.metadata()?.len(); + + let mut bytes = Lrc::new_uninit_slice(len as usize); + let mut buf = BorrowedBuf::from(Lrc::get_mut(&mut bytes).unwrap()); + file.read_buf_exact(buf.unfilled())?; + // SAFETY: If the read_buf_exact call returns Ok(()), then we have + // read len bytes and initialized the buffer. + Ok(unsafe { bytes.assume_init() }) } } @@ -228,7 +241,7 @@ impl SourceMap { /// /// Unlike `load_file`, guarantees that no normalization like BOM-removal /// takes place. - pub fn load_binary_file(&self, path: &Path) -> io::Result<Vec<u8>> { + pub fn load_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>> { let bytes = self.file_loader.read_binary_file(path)?; // We need to add file to the `SourceMap`, so that it is present diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 07bae08d558..656deebb5d0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1281,6 +1281,7 @@ symbols! { rust_eh_catch_typeinfo, rust_eh_personality, rustc, + rustc_abi, rustc_allocator, rustc_allocator_zeroed, rustc_allow_const_fn_unstable, @@ -1365,6 +1366,7 @@ symbols! { rustc_trivial_field_reads, rustc_unsafe_specialization_marker, rustc_variance, + rustc_variance_of_opaques, rustdoc, rustdoc_internals, rustdoc_missing_doc_code_examples, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 8fab13d5d5d..8d573def9bb 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -579,10 +579,9 @@ pub enum Conv { C, Rust, - /// For things unlikely to be called, where smaller caller codegen is - /// preferred over raw speed. - /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. - RustCold, + Cold, + PreserveMost, + PreserveAll, // Target-specific calling conventions. ArmAapcs, @@ -605,9 +604,7 @@ pub enum Conv { AvrInterrupt, AvrNonBlockingInterrupt, - RiscvInterrupt { - kind: RiscvInterruptKind, - }, + RiscvInterrupt { kind: RiscvInterruptKind }, } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index af455b6432f..c6135149081 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -96,7 +96,9 @@ impl ToJson for crate::abi::call::Conv { let s = match self { Self::C => "C", Self::Rust => "Rust", - Self::RustCold => "RustCold", + Self::Cold => "Cold", + Self::PreserveMost => "PreserveMost", + Self::PreserveAll => "PreserveAll", Self::ArmAapcs => "ArmAapcs", Self::CCmseNonSecureCall => "CCmseNonSecureCall", Self::Msp430Intr => "Msp430Intr", diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index 550cdf6bda6..956a5cb5c2f 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -14,15 +14,33 @@ pub enum Abi { // hashing tests. These are used in many places, so giving them stable values reduces test // churn. The specific values are meaningless. Rust, - C { unwind: bool }, - Cdecl { unwind: bool }, - Stdcall { unwind: bool }, - Fastcall { unwind: bool }, - Vectorcall { unwind: bool }, - Thiscall { unwind: bool }, - Aapcs { unwind: bool }, - Win64 { unwind: bool }, - SysV64 { unwind: bool }, + C { + unwind: bool, + }, + Cdecl { + unwind: bool, + }, + Stdcall { + unwind: bool, + }, + Fastcall { + unwind: bool, + }, + Vectorcall { + unwind: bool, + }, + Thiscall { + unwind: bool, + }, + Aapcs { + unwind: bool, + }, + Win64 { + unwind: bool, + }, + SysV64 { + unwind: bool, + }, PtxKernel, Msp430Interrupt, X86Interrupt, @@ -32,11 +50,16 @@ pub enum Abi { AvrNonBlockingInterrupt, CCmseNonSecureCall, Wasm, - System { unwind: bool }, + System { + unwind: bool, + }, RustIntrinsic, RustCall, PlatformIntrinsic, Unadjusted, + /// For things unlikely to be called, where reducing register pressure in + /// `extern "Rust"` callers is worth paying extra cost in the callee. + /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. RustCold, RiscvInterruptM, RiscvInterruptS, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f8d40c4142d..049f2bf13b8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2216,7 +2216,7 @@ impl Default for TargetOptions { mcount: "mcount".into(), llvm_mcount_intrinsic: None, llvm_abiname: "".into(), - relax_elf_relocations: true, + relax_elf_relocations: false, llvm_args: cvs![], use_ctors_section: false, eh_frame_header: true, @@ -2276,6 +2276,13 @@ impl Target { Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi, Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind }, + // The Windows x64 calling convention we use for `extern "Rust"` + // <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation> + // expects the callee to save `xmm6` through `xmm15`, but `PreserveMost` + // (that we use by default for `extern "rust-cold"`) doesn't save any of those. + // So to avoid bloating callers, just use the Rust convention here. + Abi::RustCold if self.is_like_windows && self.arch == "x86_64" => Abi::Rust, + abi => abi, } } diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index dc1e5967859..a7ed74f4721 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -69,6 +69,7 @@ pub fn target() -> Target { position_independent_executables: true, pre_link_args, override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(Cow::from).collect()), + relax_elf_relocations: true, ..Default::default() }; Target { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5e075984238..611ec6b00ef 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2743,12 +2743,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::BindingObligation(item_def_id, span) | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => { - if self.tcx.is_diagnostic_item(sym::Send, item_def_id) - || self.tcx.lang_items().sync_trait() == Some(item_def_id) - { - return; - } - let item_name = tcx.def_path_str(item_def_id); let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id)); let mut multispan = MultiSpan::from(span); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 88d03003309..8a24f96743a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -548,7 +548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.span, "GATs in trait object shouldn't have been considered", ); - return Err(SelectionError::Unimplemented); + return Err(SelectionError::TraitNotObjectSafe(trait_predicate.trait_ref.def_id)); } // This maybe belongs in wf, but that can't (doesn't) handle diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 19385e2d7f2..7e4d926dc8d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2346,14 +2346,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - let ty = self.tcx().type_of(def_id); - if ty.skip_binder().references_error() { - return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); - } // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - t.rebind(vec![ty.instantiate(self.tcx(), args)]) + match self.tcx().type_of_opaque(def_id) { + Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]), + Err(_) => { + return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); + } + } } }) } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 729cf2f3313..efab29743f4 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -472,17 +472,11 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti let mut types_without_default_bounds = FxIndexSet::default(); let sized_trait = tcx.lang_items().sized_trait(); - if !args.is_empty() { + let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>(); + if !arg_names.is_empty() { types_without_default_bounds.extend(args.types()); w.push('<'); - w.push_str( - &args - .iter() - .map(|k| k.to_string()) - .filter(|k| k != "'_") - .collect::<Vec<_>>() - .join(", "), - ); + w.push_str(&arg_names.join(", ")); w.push('>'); } diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 427ac368432..e41073937be 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -152,7 +152,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { segment_visitor(VtblSegment::TraitOwnEntries { trait_ref: inner_most_trait_ref, - emit_vptr, + emit_vptr: emit_vptr && !tcx.sess.opts.unstable_opts.no_trait_vptr, })?; // If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 4d0b847533b..a03da41652c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -172,7 +172,10 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv { use rustc_target::spec::abi::Abi::*; match tcx.sess.target.adjust_abi(abi) { RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, - RustCold => Conv::RustCold, + + // This is intentionally not using `Conv::Cold`, as that has to preserve + // even SIMD registers, which is generally not a good trade-off. + RustCold => Conv::PreserveMost, // It's the ABI's job to select this, not ours. System { .. } => bug!("system abi should be selected elsewhere"), |
