From 097f9c6b4710d16a07aaded5ae00f9c25d35d561 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding Date: Sun, 26 Oct 2025 21:57:41 +0000 Subject: [PATCH] Stop using prefix_tys This function hints at an early commitment to coroutine memory layout. We should not give promises on how upvars are allocated. Signed-off-by: Xiangfei Ding --- compiler/rustc_borrowck/src/type_check/mod.rs | 21 +- .../src/debuginfo/metadata.rs | 236 ++++++++++++------ .../src/debuginfo/metadata/enums/cpp_like.rs | 2 - .../src/debuginfo/metadata/enums/mod.rs | 35 +-- .../src/debuginfo/metadata/enums/native.rs | 4 - compiler/rustc_middle/src/mir/statement.rs | 5 +- compiler/rustc_middle/src/ty/layout.rs | 5 +- compiler/rustc_middle/src/ty/sty.rs | 7 - compiler/rustc_mir_transform/src/validate.rs | 198 +++++++++++---- compiler/rustc_ty_utils/src/layout.rs | 2 +- 10 files changed, 335 insertions(+), 180 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 13983f349d6a5..875001a37c705 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -26,8 +26,8 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt, - GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions, + self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, GenericArgsRef, Ty, TyCtxt, + TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions, }; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; @@ -2222,14 +2222,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } AggregateKind::Coroutine(_, args) => { - // It doesn't make sense to look at a field beyond the prefix; - // these require a variant index, and are not initialized in - // aggregate rvalues. - match args.as_coroutine().prefix_tys().get(field_index.as_usize()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_coroutine().prefix_tys().len(), - }), + // It doesn't make sense to look at a field beyond the captured + // upvars. + // Otherwise it require a variant index, and are not initialized + // in aggregate rvalues. + let upvar_tys = &args.as_coroutine().upvar_tys(); + if let Some(ty) = upvar_tys.get(field_index.as_usize()) { + Ok(*ty) + } else { + Err(FieldAccessError::OutOfRange { field_count: upvar_tys.len() }) } } AggregateKind::CoroutineClosure(_, args) => { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0fd47cb15f286..9d35be26a556a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -15,8 +15,7 @@ use rustc_middle::ty::layout::{ HasTypingEnv, LayoutOf, TyAndLayout, WIDE_PTR_ADDR, WIDE_PTR_EXTRA, }; use rustc_middle::ty::{ - self, AdtDef, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, - Unnormalized, Visibility, + self, AdtDef, AdtKind, ExistentialTraitRef, Instance, Ty, TyCtxt, Unnormalized, Visibility, }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::{DUMMY_SP, FileName, RemapPathScopeComponents, SourceFile, Span, Symbol, hygiene}; @@ -80,7 +79,10 @@ mod type_map; /// unique ID can be found in the type map. macro_rules! return_if_di_node_created_in_meantime { ($cx: expr, $unique_type_id: expr) => { - if let Some(di_node) = debug_context($cx).type_map.di_node_for_unique_id($unique_type_id) { + if let Some(di_node) = debug_context($cx) + .type_map + .di_node_for_unique_id($unique_type_id) + { return DINodeCreationResult::new(di_node, true); } }; @@ -101,7 +103,10 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( span: Span, ) -> DINodeCreationResult<'ll> { let ty::Array(element_type, len) = array_type.kind() else { - bug!("build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", array_type) + bug!( + "build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", + array_type + ) }; let element_type_di_node = spanned_type_di_node(cx, *element_type, span); @@ -178,7 +183,10 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( &ptr_type_debuginfo_name, ); - DINodeCreationResult { di_node, already_stored_in_typemap: false } + DINodeCreationResult { + di_node, + already_stored_in_typemap: false, + } } Some(wide_pointer_kind) => { type_map::build_type_with_children( @@ -284,8 +292,9 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( .insert(unique_type_id, recursion_marker_type_di_node(cx)); let fn_ty = unique_type_id.expect_ty(); - let signature = - cx.tcx.normalize_erasing_late_bound_regions(cx.typing_env(), fn_ty.fn_sig(cx.tcx)); + let signature = cx + .tcx + .normalize_erasing_late_bound_regions(cx.typing_env(), fn_ty.fn_sig(cx.tcx)); let signature_di_nodes: SmallVec<_> = iter::once( // return type @@ -299,11 +308,18 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( ) .chain( // regular arguments - signature.inputs().iter().map(|&argument_type| Some(type_di_node(cx, argument_type))), + signature + .inputs() + .iter() + .map(|&argument_type| Some(type_di_node(cx, argument_type))), ) .collect(); - debug_context(cx).type_map.unique_id_to_di_node.borrow_mut().remove(&unique_type_id); + debug_context(cx) + .type_map + .unique_id_to_di_node + .borrow_mut() + .remove(&unique_type_id); let fn_di_node = create_subroutine_type(cx, &signature_di_nodes[..]); @@ -311,9 +327,10 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false); let (size, align) = match fn_ty.kind() { ty::FnDef(..) => (Size::ZERO, Align::ONE), - ty::FnPtr(..) => { - (cx.tcx.data_layout.pointer_size(), cx.tcx.data_layout.pointer_align().abi) - } + ty::FnPtr(..) => ( + cx.tcx.data_layout.pointer_size(), + cx.tcx.data_layout.pointer_align().abi, + ), _ => unreachable!(), }; let di_node = create_pointer_type(cx, fn_di_node, size, align, &name); @@ -423,7 +440,10 @@ fn build_slice_type_di_node<'ll, 'tcx>( let element_type_di_node = type_di_node(cx, element_type); return_if_di_node_created_in_meantime!(cx, unique_type_id); - DINodeCreationResult { di_node: element_type_di_node, already_stored_in_typemap: false } + DINodeCreationResult { + di_node: element_type_di_node, + already_stored_in_typemap: false, + } } /// Get the debuginfo node for the given type. @@ -441,14 +461,19 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( ) -> &'ll DIType { let unique_type_id = UniqueTypeId::for_ty(cx.tcx, t); - if let Some(existing_di_node) = debug_context(cx).type_map.di_node_for_unique_id(unique_type_id) + if let Some(existing_di_node) = debug_context(cx) + .type_map + .di_node_for_unique_id(unique_type_id) { return existing_di_node; } debug!("type_di_node: {:?} kind: {:?}", t, t.kind()); - let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() { + let DINodeCreationResult { + di_node, + already_stored_in_typemap, + } = match *t.kind() { ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { build_basic_type_di_node(cx, t) } @@ -465,7 +490,9 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( // (or if there is no allocator argument). ty::Adt(def, args) if def.is_box() - && args.get(1).is_none_or(|arg| cx.layout_of(arg.expect_ty()).is_1zst()) => + && args + .get(1) + .is_none_or(|arg| cx.layout_of(arg.expect_ty()).is_1zst()) => { build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id) } @@ -495,19 +522,21 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( { if already_stored_in_typemap { // Make sure that we really do have a `TypeMap` entry for the unique type ID. - let di_node_for_uid = - match debug_context(cx).type_map.di_node_for_unique_id(unique_type_id) { - Some(di_node) => di_node, - None => { - bug!( - "expected type debuginfo node for unique \ + let di_node_for_uid = match debug_context(cx) + .type_map + .di_node_for_unique_id(unique_type_id) + { + Some(di_node) => di_node, + None => { + bug!( + "expected type debuginfo node for unique \ type ID '{:?}' to already be in \ the `debuginfo::TypeMap` but it \ was not.", - unique_type_id, - ); - } - }; + unique_type_id, + ); + } + }; assert_eq!(di_node_for_uid as *const _, di_node as *const _); } else { @@ -520,24 +549,26 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( // FIXME(mw): Cache this via a regular UniqueTypeId instead of an extra field in the debug context. fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType { - *debug_context(cx).recursion_marker_type.get_or_init(move || { - // The choice of type here is pretty arbitrary - - // anything reading the debuginfo for a recursive - // type is going to see *something* weird - the only - // question is what exactly it will see. - // - // FIXME: the name `` does not fit the naming scheme - // of other types. - // - // FIXME: it might make sense to use an actual pointer type here - // so that debuggers can show the address. - create_basic_type( - cx, - "", - cx.tcx.data_layout.pointer_size(), - dwarf_const::DW_ATE_unsigned, - ) - }) + *debug_context(cx) + .recursion_marker_type + .get_or_init(move || { + // The choice of type here is pretty arbitrary - + // anything reading the debuginfo for a recursive + // type is going to see *something* weird - the only + // question is what exactly it will see. + // + // FIXME: the name `` does not fit the naming scheme + // of other types. + // + // FIXME: it might make sense to use an actual pointer type here + // so that debuggers can show the address. + create_basic_type( + cx, + "", + cx.tcx.data_layout.pointer_size(), + dwarf_const::DW_ATE_unsigned, + ) + }) } fn hex_encode(data: &[u8]) -> String { @@ -587,14 +618,22 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi // By moving the working directory portion into the `directory` part of the // DIFile, we allow LLVM to emit just the relative path for DWARF, while // still emitting the correct absolute path for CodeView. - (working_directory.to_string_lossy(), rel_path.to_string_lossy().into_owned()) + ( + working_directory.to_string_lossy(), + rel_path.to_string_lossy().into_owned(), + ) } else { ("".into(), embeddable_name.to_string_lossy().into_owned()) } } other => { debug!(?other); - ("".into(), other.display(RemapPathScopeComponents::DEBUGINFO).to_string()) + ( + "".into(), + other + .display(RemapPathScopeComponents::DEBUGINFO) + .to_string(), + ) } }; @@ -611,20 +650,34 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi if cx.sess().opts.unstable_opts.embed_source { source = source_file.src.as_deref().map(String::as_str); if source.is_none() { - cx.tcx.sess.source_map().ensure_source_file_source_present(source_file); + cx.tcx + .sess + .source_map() + .ensure_source_file_source_present(source_file); external_src = source_file.external_src.read(); source = external_src.get_source(); } } - create_file(DIB(cx), &file_name, &directory, &hash_value, hash_kind, source) + create_file( + DIB(cx), + &file_name, + &directory, + &hash_value, + hash_kind, + source, + ) } } fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { - debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| { - create_file(DIB(cx), "", "", "", llvm::ChecksumKind::None, None) - }) + debug_context(cx) + .created_files + .borrow_mut() + .entry(None) + .or_insert_with(|| { + create_file(DIB(cx), "", "", "", llvm::ChecksumKind::None, None) + }) } fn create_file<'ll>( @@ -905,20 +958,32 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( codegen_unit_name, ) { // We get a path relative to the working directory from split_dwarf_path - Some(tcx.sess.source_map().path_mapping().to_real_filename(work_dir, f)) + Some( + tcx.sess + .source_map() + .path_mapping() + .to_real_filename(work_dir, f), + ) } else { None }; let split_name = split_name .as_ref() - .map(|f| f.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy()) + .map(|f| { + f.path(RemapPathScopeComponents::DEBUGINFO) + .to_string_lossy() + }) .unwrap_or_default(); - let work_dir = work_dir.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy(); + let work_dir = work_dir + .path(RemapPathScopeComponents::DEBUGINFO) + .to_string_lossy(); let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); let dwarf_version = tcx.sess.dwarf_version(); - let is_dwarf_kind = - matches!(tcx.sess.target.debuginfo_kind, DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym); + let is_dwarf_kind = matches!( + tcx.sess.target.debuginfo_kind, + DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym + ); // Don't emit `.debug_pubnames` and `.debug_pubtypes` on DWARFv4 or lower. let debug_name_table_kind = if is_dwarf_kind && dwarf_version <= 4 { DebugNameTableKind::None @@ -1048,7 +1113,10 @@ fn build_struct_type_di_node<'ll, 'tcx>( let struct_type = unique_type_id.expect_ty(); let ty::Adt(adt_def, _) = struct_type.kind() else { - bug!("build_struct_type_di_node() called with non-struct-type: {:?}", struct_type); + bug!( + "build_struct_type_di_node() called with non-struct-type: {:?}", + struct_type + ); }; assert!(adt_def.is_struct()); let containing_scope = get_namespace_for_item(cx, adt_def.did()); @@ -1164,7 +1232,10 @@ fn build_scalable_vector_di_node<'ll, 'tcx>( }; let (bitstride, element_di_node) = if element_ty.is_bool() { - (Some(llvm::LLVMValueAsMetadata(cx.const_i64(1))), type_di_node(cx, cx.tcx.types.u8)) + ( + Some(llvm::LLVMValueAsMetadata(cx.const_i64(1))), + type_di_node(cx, cx.tcx.types.u8), + ) } else { (None, type_di_node(cx, element_ty)) }; @@ -1215,7 +1286,10 @@ fn build_scalable_vector_di_node<'ll, 'tcx>( }; debug_context(cx).type_map.insert(unique_type_id, metadata); - DINodeCreationResult { di_node: metadata, already_stored_in_typemap: true } + DINodeCreationResult { + di_node: metadata, + already_stored_in_typemap: true, + } } //=----------------------------------------------------------------------------- @@ -1230,7 +1304,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>( closure_or_coroutine_di_node: &'ll DIType, ) -> SmallVec<&'ll DIType> { let (&def_id, up_var_tys) = match closure_or_coroutine_ty.kind() { - ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().prefix_tys()), + ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().upvar_tys()), ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()), ty::CoroutineClosure(def_id, args) => (def_id, args.as_coroutine_closure().upvar_tys()), _ => { @@ -1274,7 +1348,10 @@ fn build_tuple_type_di_node<'ll, 'tcx>( ) -> DINodeCreationResult<'ll> { let tuple_type = unique_type_id.expect_ty(); let &ty::Tuple(component_types) = tuple_type.kind() else { - bug!("build_tuple_type_di_node() called with non-tuple-type: {:?}", tuple_type) + bug!( + "build_tuple_type_di_node() called with non-tuple-type: {:?}", + tuple_type + ) }; let tuple_type_and_layout = cx.layout_of(tuple_type); @@ -1323,7 +1400,10 @@ fn build_closure_env_di_node<'ll, 'tcx>( let closure_env_type = unique_type_id.expect_ty(); let &(ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _)) = closure_env_type.kind() else { - bug!("build_closure_env_di_node() called with non-closure-type: {:?}", closure_env_type) + bug!( + "build_closure_env_di_node() called with non-closure-type: {:?}", + closure_env_type + ) }; let containing_scope = get_namespace_for_item(cx, def_id); let type_name = compute_debuginfo_type_name(cx.tcx, closure_env_type, false); @@ -1443,9 +1523,9 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( return smallvec![]; fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec { - let mut names = generics - .parent - .map_or_else(Vec::new, |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id))); + let mut names = generics.parent.map_or_else(Vec::new, |def_id| { + get_parameter_names(cx, cx.tcx.generics_of(def_id)) + }); names.extend(generics.own_params.iter().map(|param| param.name)); names } @@ -1477,7 +1557,9 @@ pub(crate) fn build_global_var_di_node<'ll>( let is_local_to_unit = is_node_local_to_unit(cx, def_id); - let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { bug!() }; + let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { + bug!() + }; if nested { return; } @@ -1488,7 +1570,11 @@ pub(crate) fn build_global_var_di_node<'ll>( let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name; // When empty, linkage_name field is omitted, // which is what we want for no_mangle statics - let linkage_name = if var_name == linkage_name { "" } else { linkage_name }; + let linkage_name = if var_name == linkage_name { + "" + } else { + linkage_name + }; let global_align = cx.align_of(variable_type); @@ -1542,7 +1628,10 @@ fn build_vtable_type_di_node<'ll, 'tcx>( // If `usize` is not pointer-sized and -aligned then the size and alignment computations // for the vtable as a whole would be wrong. Let's make sure this holds even on weird // platforms. - assert_eq!(cx.size_and_align_of(tcx.types.usize), (pointer_size, pointer_align)); + assert_eq!( + cx.size_and_align_of(tcx.types.usize), + (pointer_size, pointer_align) + ); let vtable_type_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type); @@ -1580,9 +1669,10 @@ fn build_vtable_type_di_node<'ll, 'tcx>( // (coming from different traits). (format!("__method{index}"), void_pointer_type_di_node) } - ty::VtblEntry::TraitVPtr(_) => { - (format!("__super_trait_ptr{index}"), void_pointer_type_di_node) - } + ty::VtblEntry::TraitVPtr(_) => ( + format!("__super_trait_ptr{index}"), + void_pointer_type_di_node, + ), ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_di_node), ty::VtblEntry::MetadataSize => ("size".to_string(), usize_di_node), ty::VtblEntry::Vacant => return None, @@ -1735,7 +1825,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; cx.global_add_metadata_node(vtable, llvm::MD_type, &type_); - let vcall_visibility = [llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64))]; + let vcall_visibility = [llvm::LLVMValueAsMetadata( + cx.const_u64(vcall_visibility as u64), + )]; cx.global_set_metadata_node(vtable, llvm::MD_vcall_visibility, &vcall_visibility); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 348c54b00ba97..8d1b1a8f7c03e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -721,7 +721,6 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>( let coroutine_layout = cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args.args).unwrap(); - let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id); let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx); let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len(); @@ -761,7 +760,6 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>( coroutine_type_and_layout, coroutine_type_di_node, coroutine_layout, - common_upvar_names, ); let span = coroutine_layout.variant_source_info[variant_index].span; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 556158c286a84..d81f80d87d930 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -5,12 +5,11 @@ use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_ use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo}; use rustc_codegen_ssa::traits::MiscCodegenMethods; use rustc_hir::def::CtorKind; -use rustc_index::IndexSlice; use rustc_middle::bug; use rustc_middle::mir::CoroutineLayout; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; use super::type_map::{DINodeCreationResult, UniqueTypeId}; use super::{SmallVec, size_and_align_of}; @@ -287,7 +286,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( coroutine_type_and_layout: TyAndLayout<'tcx>, coroutine_type_di_node: &'ll DIType, coroutine_layout: &CoroutineLayout<'tcx>, - common_upvar_names: &IndexSlice, ) -> &'ll DIType { let variant_name = CoroutineArgs::variant_name(variant_index); let unique_type_id = UniqueTypeId::for_enum_variant_struct_type( @@ -298,11 +296,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( let variant_layout = coroutine_type_and_layout.for_variant(cx, variant_index); - let coroutine_args = match coroutine_type_and_layout.ty.kind() { - ty::Coroutine(_, args) => args.as_coroutine(), - _ => unreachable!(), - }; - type_map::build_type_with_children( cx, type_map::stub( @@ -317,7 +310,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( ), |cx, variant_struct_type_di_node| { // Fields that just belong to this variant/state - let state_specific_fields: SmallVec<_> = (0..variant_layout.fields.count()) + (0..variant_layout.fields.count()) .map(|field_index| { let coroutine_saved_local = coroutine_layout.variant_fields[variant_index] [FieldIdx::from_usize(field_index)]; @@ -340,29 +333,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( None, ) }) - .collect(); - - // Fields that are common to all states - let common_fields: SmallVec<_> = coroutine_args - .prefix_tys() - .iter() - .zip(common_upvar_names) - .enumerate() - .map(|(index, (upvar_ty, upvar_name))| { - build_field_di_node( - cx, - variant_struct_type_di_node, - upvar_name.as_str(), - cx.layout_of(upvar_ty), - coroutine_type_and_layout.fields.offset(index), - DIFlags::FlagZero, - type_di_node(cx, upvar_ty), - None, - ) - }) - .collect(); - - state_specific_fields.into_iter().chain(common_fields).collect() + .collect() }, |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty), ) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index a3299af35ac21..e12b1811fa0c0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -185,9 +185,6 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>( ) }; - let common_upvar_names = - cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id); - // Build variant struct types let variant_struct_type_di_nodes: SmallVec<_> = variants .indices() @@ -215,7 +212,6 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>( coroutine_type_and_layout, coroutine_type_di_node, coroutine_layout, - common_upvar_names, ), source_info, } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 4c619f825fa8b..b0cdb1b7164c7 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -157,10 +157,9 @@ impl<'tcx> PlaceTy<'tcx> { .copied() .unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")), ), - // Only prefix fields (upvars and current state) are - // accessible without a variant index. + // Only upvars are accessible without a variant index. ty::Coroutine(_, args) => Unnormalized::dummy( - args.as_coroutine().prefix_tys().get(f.index()).copied().unwrap_or_else(|| { + args.as_coroutine().upvar_tys().get(f.index()).copied().unwrap_or_else(|| { bug!("field {f:?} out of range of prefixes for {self_ty}") }), ), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index e2fc663852374..877e5b848b30a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -938,9 +938,10 @@ where ), Variants::Multiple { tag, tag_field, .. } => { if FieldIdx::from_usize(i) == tag_field { - return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); + TyMaybeWithLayout::TyAndLayout(tag_layout(tag)) + } else { + TyMaybeWithLayout::Ty(args.as_coroutine().upvar_tys()[i]) } - TyMaybeWithLayout::Ty(args.as_coroutine().prefix_tys()[i]) } }, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 14bce52fefe63..9c31786202659 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -168,13 +168,6 @@ impl<'tcx> ty::CoroutineArgs> { }) }) } - - /// This is the types of the fields of a coroutine which are not stored in a - /// variant. - #[inline] - fn prefix_tys(self) -> &'tcx List> { - self.upvar_tys() - } } #[derive(Debug, Copy, Clone, StableHash, TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 132dea85e4372..9774eeb40079f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -14,8 +14,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Unnormalized, - Upcast, Variance, + self, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Unnormalized, Upcast, Variance, }; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::debuginfo::debuginfo_locals; @@ -40,7 +39,10 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { // terribly important that they pass the validator. However, I think other passes might // still see them, in which case they might be surprised. It would probably be better if we // didn't put this through the MIR pipeline at all. - if matches!(body.source.instance, InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..)) { + if matches!( + body.source.instance, + InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..) + ) { return; } let def_id = body.source.def_id(); @@ -167,7 +169,10 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { } } } else { - self.fail(location, format!("encountered jump to invalid basic block {bb:?}")) + self.fail( + location, + format!("encountered jump to invalid basic block {bb:?}"), + ) } } @@ -282,8 +287,10 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { fn is_critical_call_edge(&self, target: Option, unwind: UnwindAction) -> bool { let Some(target) = target else { return false }; - matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate(_)) - && self.body.basic_blocks.predecessors()[target].len() > 1 + matches!( + unwind, + UnwindAction::Cleanup(_) | UnwindAction::Terminate(_) + ) && self.body.basic_blocks.predecessors()[target].len() > 1 } } @@ -317,7 +324,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } StatementKind::SetDiscriminant { .. } => { if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`SetDiscriminant`is not allowed until deaggregation"); + self.fail( + location, + "`SetDiscriminant`is not allowed until deaggregation", + ); } } StatementKind::Coverage(kind) => { @@ -355,7 +365,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.check_edge(location, targets.otherwise(), EdgeKind::Normal); self.value_cache.clear(); - self.value_cache.extend(targets.iter().map(|(value, _)| value)); + self.value_cache + .extend(targets.iter().map(|(value, _)| value)); let has_duplicates = targets.iter().len() != self.value_cache.len(); if has_duplicates { self.fail( @@ -367,7 +378,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { ); } } - TerminatorKind::Drop { target, unwind, drop, .. } => { + TerminatorKind::Drop { + target, + unwind, + drop, + .. + } => { self.check_edge(location, *target, EdgeKind::Normal); self.check_unwind_edge(location, *unwind); if let Some(drop) = drop { @@ -377,7 +393,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { TerminatorKind::Call { func, args, .. } | TerminatorKind::TailCall { func, args, .. } => { // FIXME(explicit_tail_calls): refactor this & add tail-call specific checks - if let TerminatorKind::Call { target, unwind, destination, .. } = terminator.kind { + if let TerminatorKind::Call { + target, + unwind, + destination, + .. + } = terminator.kind + { if let Some(target) = target { self.check_edge(location, target, EdgeKind::Normal); } @@ -435,9 +457,15 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { if let ty::FnDef(did, ..) = *func.ty(&self.body.local_decls, self.tcx).kind() && self.body.phase >= MirPhase::Runtime(RuntimePhase::Optimized) - && matches!(self.tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. }) + && matches!( + self.tcx.codegen_fn_attrs(did).inline, + InlineAttr::Force { .. } + ) { - self.fail(location, "`#[rustc_force_inline]`-annotated function not inlined"); + self.fail( + location, + "`#[rustc_force_inline]`-annotated function not inlined", + ); } } TerminatorKind::Assert { target, unwind, .. } => { @@ -449,14 +477,20 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.fail(location, "`Yield` cannot appear outside coroutine bodies"); } if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`Yield` should have been replaced by coroutine lowering"); + self.fail( + location, + "`Yield` should have been replaced by coroutine lowering", + ); } self.check_edge(location, *resume, EdgeKind::Normal); if let Some(drop) = drop { self.check_edge(location, *drop, EdgeKind::Normal); } } - TerminatorKind::FalseEdge { real_target, imaginary_target } => { + TerminatorKind::FalseEdge { + real_target, + imaginary_target, + } => { if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, @@ -466,7 +500,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.check_edge(location, *real_target, EdgeKind::Normal); self.check_edge(location, *imaginary_target, EdgeKind::Normal); } - TerminatorKind::FalseUnwind { real_target, unwind } => { + TerminatorKind::FalseUnwind { + real_target, + unwind, + } => { if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, @@ -476,7 +513,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.check_edge(location, *real_target, EdgeKind::Normal); self.check_unwind_edge(location, *unwind); } - TerminatorKind::InlineAsm { targets, unwind, .. } => { + TerminatorKind::InlineAsm { + targets, unwind, .. + } => { for &target in targets { self.check_edge(location, target, EdgeKind::Normal); } @@ -484,7 +523,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } TerminatorKind::CoroutineDrop => { if self.body.coroutine.is_none() { - self.fail(location, "`CoroutineDrop` cannot appear outside coroutine bodies"); + self.fail( + location, + "`CoroutineDrop` cannot appear outside coroutine bodies", + ); } if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( @@ -496,16 +538,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { TerminatorKind::UnwindResume => { let bb = location.block; if !self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `UnwindResume` from non-cleanup basic block") + self.fail( + location, + "Cannot `UnwindResume` from non-cleanup basic block", + ) } if !self.can_unwind { - self.fail(location, "Cannot `UnwindResume` in a function that cannot unwind") + self.fail( + location, + "Cannot `UnwindResume` in a function that cannot unwind", + ) } } TerminatorKind::UnwindTerminate(_) => { let bb = location.block; if !self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `UnwindTerminate` from non-cleanup basic block") + self.fail( + location, + "Cannot `UnwindTerminate` from non-cleanup basic block", + ) } } TerminatorKind::Return => { @@ -544,7 +595,13 @@ pub(super) fn validate_types<'tcx>( body: &Body<'tcx>, caller_body: &Body<'tcx>, ) -> Vec<(Location, String)> { - let mut type_checker = TypeChecker { body, caller_body, tcx, typing_env, failures: Vec::new() }; + let mut type_checker = TypeChecker { + body, + caller_body, + tcx, + typing_env, + failures: Vec::new(), + }; // The type checker formats a bunch of strings with type names in it, but these strings // are not always going to be encountered on the error path since the inliner also uses // the validator, and there are certain kinds of inlining (even for valid code) that @@ -636,7 +693,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let ty = place.ty(&self.body.local_decls, self.tcx).ty; if !self.tcx.type_is_copy_modulo_regions(self.typing_env, ty) { - self.fail(location, format!("`Operand::Copy` with non-`Copy` type {ty}")); + self.fail( + location, + format!("`Operand::Copy` with non-`Copy` type {ty}"), + ); } } } @@ -658,13 +718,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty; if base_ty.is_box() { - self.fail(location, format!("{base_ty} dereferenced after ElaborateBoxDerefs")) + self.fail( + location, + format!("{base_ty} dereferenced after ElaborateBoxDerefs"), + ) } } ProjectionElem::Field(f, ty) => { let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx); let fail_out_of_bounds = |this: &mut Self, location| { - this.fail(location, format!("Out of bounds field {f:?} for {parent_ty:?}")); + this.fail( + location, + format!("Out of bounds field {f:?} for {parent_ty:?}"), + ); }; let check_equal = |this: &mut Self, location, f_ty| { if !this.mir_assign_valid_types(ty, f_ty) { @@ -678,9 +744,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; let kind = match parent_ty.ty.kind() { - &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => { - self.tcx.type_of(def_id).instantiate(self.tcx, args).skip_norm_wip().kind() - } + &ty::Alias(ty::AliasTy { + kind: ty::Opaque { def_id }, + args, + .. + }) => self + .tcx + .type_of(def_id) + .instantiate(self.tcx, args) + .skip_norm_wip() + .kind(), kind => kind, }; @@ -785,14 +858,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ty::EarlyBinder::bind(f_ty.ty) .instantiate(self.tcx, args) .skip_norm_wip() - } else { - let Some(&f_ty) = args.as_coroutine().prefix_tys().get(f.index()) - else { - fail_out_of_bounds(self, location); - return; - }; - + } else if let Some(&f_ty) = args.as_coroutine().upvar_tys().get(f.index()) { f_ty + } else { + fail_out_of_bounds(self, location); + return; }; check_equal(self, location, f_ty); @@ -814,7 +884,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, format!("bad index ({index_ty} != usize)")) } } - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { + offset, + min_length, + from_end, + } => { let indexed_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty; match indexed_ty.kind() { ty::Array(_, _) => { @@ -909,10 +983,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if projection.is_empty() { self.fail( START_BLOCK.start_location(), - format!("invalid empty projection in debuginfo for {:?}", debuginfo.name), + format!( + "invalid empty projection in debuginfo for {:?}", + debuginfo.name + ), ); } - if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { + if projection + .iter() + .any(|p| !matches!(p, PlaceElem::Field(..))) + { self.fail( START_BLOCK.start_location(), format!( @@ -928,7 +1008,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { self.fail( START_BLOCK.start_location(), - format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + format!( + "illegal place {:?} in debuginfo for {:?}", + place, debuginfo.name + ), ); } } @@ -1014,7 +1097,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Use(_, _) => {} Rvalue::CopyForDeref(_) => { if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`CopyForDeref` should have been removed in runtime MIR"); + self.fail( + location, + "`CopyForDeref` should have been removed in runtime MIR", + ); } } Rvalue::Aggregate(kind, fields) => match **kind { @@ -1066,7 +1152,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { AggregateKind::Closure(_, args) => { let upvars = args.as_closure().upvar_tys(); if upvars.len() != fields.len() { - self.fail(location, "closure has the wrong number of initialized fields"); + self.fail( + location, + "closure has the wrong number of initialized fields", + ); } for (src, dest) in std::iter::zip(fields, upvars) { if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { @@ -1077,7 +1166,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { AggregateKind::Coroutine(_, args) => { let upvars = args.as_coroutine().upvar_tys(); if upvars.len() != fields.len() { - self.fail(location, "coroutine has the wrong number of initialized fields"); + self.fail( + location, + "coroutine has the wrong number of initialized fields", + ); } for (src, dest) in std::iter::zip(fields, upvars) { if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { @@ -1479,7 +1571,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.body.local_decls[local].local_info && !matches!(rvalue, Rvalue::CopyForDeref(_)) { - self.fail(location, "assignment to a `DerefTemp` must use `CopyForDeref`") + self.fail( + location, + "assignment to a `DerefTemp` must use `CopyForDeref`", + ) } } StatementKind::AscribeUserType(..) => { @@ -1543,14 +1638,20 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } StatementKind::SetDiscriminant { place, .. } => { if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`SetDiscriminant`is not allowed until deaggregation"); + self.fail( + location, + "`SetDiscriminant`is not allowed until deaggregation", + ); } let pty = place.ty(&self.body.local_decls, self.tcx).ty; if !matches!( pty.kind(), ty::Adt(..) | ty::Coroutine(..) - | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) + | ty::Alias(ty::AliasTy { + kind: ty::Opaque { .. }, + .. + }) ) { self.fail( location, @@ -1661,8 +1762,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } pub(super) fn validate_debuginfos<'tcx>(body: &Body<'tcx>) -> Vec<(Location, String)> { - let mut debuginfo_checker = - DebuginfoChecker { debuginfo_locals: debuginfo_locals(body), failures: Vec::new() }; + let mut debuginfo_checker = DebuginfoChecker { + debuginfo_locals: debuginfo_locals(body), + failures: Vec::new(), + }; debuginfo_checker.visit_body(body); debuginfo_checker.failures } @@ -1682,7 +1785,8 @@ impl<'tcx> Visitor<'tcx> for DebuginfoChecker { StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => *local, }; if !self.debuginfo_locals.contains(local) { - self.failures.push((location, format!("{local:?} is not in debuginfo"))); + self.failures + .push((location, format!("{local:?} is not in debuginfo"))); } } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9cc15a374ff70..62fe56dc7e84e 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -536,7 +536,7 @@ fn layout_of_uncached<'tcx>( let prefix_layouts = args .as_coroutine() - .prefix_tys() + .upvar_tys() .iter() .map(|ty| cx.layout_of(ty)) .try_collect::>()?;