diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 8a957a729fb68..33351c06d27ee 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -33,9 +33,9 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::truncate; use rustc_middle::mir::{self, Field, GeneratorLayout}; use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout}; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::Instance; -use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::{Interner, Symbol}; @@ -392,6 +392,7 @@ fn vec_slice_metadata( align: pointer_align, flags: DIFlags::FlagZero, discriminant: None, + source_info: None, }, MemberDescription { name: "length".to_owned(), @@ -401,6 +402,7 @@ fn vec_slice_metadata( align: usize_align, flags: DIFlags::FlagZero, discriminant: None, + source_info: None, }, ]; @@ -508,6 +510,7 @@ fn trait_pointer_metadata( align: data_ptr_field.align.abi, flags: DIFlags::FlagArtificial, discriminant: None, + source_info: None, }, MemberDescription { name: "vtable".to_owned(), @@ -517,6 +520,7 @@ fn trait_pointer_metadata( align: vtable_field.align.abi, flags: DIFlags::FlagArtificial, discriminant: None, + source_info: None, }, ]; @@ -859,7 +863,7 @@ fn foreign_type_metadata( debug!("foreign_type_metadata: {:?}", t); let name = compute_debuginfo_type_name(cx.tcx, t, false); - create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA) + create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero) } fn pointer_type_metadata( @@ -1026,6 +1030,12 @@ impl MetadataCreationResult<'ll> { } } +#[derive(Debug)] +struct SourceInfo<'ll> { + file: &'ll DIFile, + line: u32, +} + /// Description of a type member, which can either be a regular field (as in /// structs or tuples) or an enum variant. #[derive(Debug)] @@ -1037,6 +1047,7 @@ struct MemberDescription<'ll> { align: Align, flags: DIFlags, discriminant: Option, + source_info: Option>, } impl<'ll> MemberDescription<'ll> { @@ -1045,14 +1056,18 @@ impl<'ll> MemberDescription<'ll> { cx: &CodegenCx<'ll, '_>, composite_type_metadata: &'ll DIScope, ) -> &'ll DIType { + let (file, line) = self + .source_info + .map(|info| (info.file, info.line)) + .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)); unsafe { llvm::LLVMRustDIBuilderCreateVariantMemberType( DIB(cx), composite_type_metadata, self.name.as_ptr().cast(), self.name.len(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, + file, + line, self.size.bits(), self.align.bits() as u32, self.offset.bits(), @@ -1124,6 +1139,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { align: field.align.abi, flags: DIFlags::FlagZero, discriminant: None, + source_info: None, } }) .collect() @@ -1145,8 +1161,14 @@ fn prepare_struct_metadata( let containing_scope = get_namespace_for_item(cx, struct_def_id); - let struct_metadata_stub = - create_struct_stub(cx, struct_type, &struct_name, unique_type_id, Some(containing_scope)); + let struct_metadata_stub = create_struct_stub( + cx, + struct_type, + &struct_name, + unique_type_id, + Some(containing_scope), + DIFlags::FlagZero, + ); create_and_register_recursive_type_forward_declaration( cx, @@ -1185,6 +1207,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> { align, flags: DIFlags::FlagZero, discriminant: None, + source_info: None, } }) .collect() @@ -1201,8 +1224,14 @@ fn prepare_tuple_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); - let struct_stub = - create_struct_stub(cx, tuple_type, &tuple_name[..], unique_type_id, containing_scope); + let struct_stub = create_struct_stub( + cx, + tuple_type, + &tuple_name[..], + unique_type_id, + containing_scope, + DIFlags::FlagZero, + ); create_and_register_recursive_type_forward_declaration( cx, @@ -1244,6 +1273,7 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> { align: field.align.abi, flags: DIFlags::FlagZero, discriminant: None, + source_info: None, } }) .collect() @@ -1351,11 +1381,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { let variant_info_for = |index: VariantIdx| match self.enum_type.kind { ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]), - ty::Generator(_, substs, _) => { + ty::Generator(def_id, _, _) => { let (generator_layout, generator_saved_local_names) = generator_variant_info_data.as_ref().unwrap(); VariantInfo::Generator { - substs, + def_id, generator_layout: *generator_layout, generator_saved_local_names, variant_index: index, @@ -1371,6 +1401,10 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } else { type_metadata(cx, self.enum_type, self.span) }; + let flags = match self.enum_type.kind { + ty::Generator(..) => DIFlags::FlagArtificial, + _ => DIFlags::FlagZero, + }; match self.layout.variants { Variants::Single { index } => { @@ -1404,8 +1438,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: self.layout.size, align: self.layout.align.abi, - flags: DIFlags::FlagZero, + flags, discriminant: None, + source_info: variant_info.source_info(cx), }] } Variants::Multiple { @@ -1457,11 +1492,12 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: self.layout.size, align: self.layout.align.abi, - flags: DIFlags::FlagZero, + flags, discriminant: Some( self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val as u64, ), + source_info: variant_info.source_info(cx), } }) .collect() @@ -1527,7 +1563,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { self.layout.fields.offset(tag_field), self.layout.field(cx, tag_field).size, ); - variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| { + let variant_info = variant_info_for(*niche_variants.start()); + variant_info.map_struct_name(|variant_name| { name.push_str(variant_name); }); @@ -1538,8 +1575,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: variant.size, align: variant.align.abi, - flags: DIFlags::FlagZero, + flags, discriminant: None, + source_info: variant_info.source_info(cx), }] } else { variants @@ -1587,8 +1625,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: self.layout.size, align: self.layout.align.abi, - flags: DIFlags::FlagZero, + flags, discriminant: niche_value, + source_info: variant_info.source_info(cx), } }) .collect() @@ -1613,24 +1652,27 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { .iter() .enumerate() .map(|(i, &(ref name, ty))| { + // Discriminant is always the first field of our variant + // when using the enum fallback. + let is_artificial_discr = use_enum_fallback(cx) && i == 0; let (size, align) = cx.size_and_align_of(ty); MemberDescription { name: name.to_string(), - type_metadata: if use_enum_fallback(cx) { - match self.tag_type_metadata { - // Discriminant is always the first field of our variant - // when using the enum fallback. - Some(metadata) if i == 0 => metadata, - _ => type_metadata(cx, ty, self.span), - } + type_metadata: if is_artificial_discr { + self.tag_type_metadata.unwrap_or_else(|| type_metadata(cx, ty, self.span)) } else { type_metadata(cx, ty, self.span) }, offset: self.offsets[i], size, align, - flags: DIFlags::FlagZero, + flags: if is_artificial_discr { + DIFlags::FlagArtificial + } else { + DIFlags::FlagZero + }, discriminant: None, + source_info: None, } }) .collect() @@ -1651,7 +1693,7 @@ enum EnumTagInfo<'ll> { enum VariantInfo<'a, 'tcx> { Adt(&'tcx ty::VariantDef), Generator { - substs: SubstsRef<'tcx>, + def_id: DefId, generator_layout: &'tcx GeneratorLayout<'tcx>, generator_saved_local_names: &'a IndexVec>, variant_index: VariantIdx, @@ -1662,8 +1704,8 @@ impl<'tcx> VariantInfo<'_, 'tcx> { fn map_struct_name(&self, f: impl FnOnce(&str) -> R) -> R { match self { VariantInfo::Adt(variant) => f(&variant.ident.as_str()), - VariantInfo::Generator { substs, variant_index, .. } => { - f(&substs.as_generator().variant_name(*variant_index)) + VariantInfo::Generator { variant_index, .. } => { + f(&GeneratorSubsts::variant_name(*variant_index)) } } } @@ -1699,6 +1741,32 @@ impl<'tcx> VariantInfo<'_, 'tcx> { }; field_name.map(|name| name.to_string()).unwrap_or_else(|| format!("__{}", i)) } + + fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option> { + match self { + VariantInfo::Generator { def_id, variant_index, .. } => { + let span = + cx.tcx.generator_layout(*def_id).variant_source_info[*variant_index].span; + if !span.is_dummy() { + let loc = cx.lookup_debug_loc(span.lo()); + return Some(SourceInfo { + file: file_metadata(cx, &loc.file, def_id.krate), + line: loc.line.unwrap_or(UNKNOWN_LINE_NUMBER), + }); + } + } + _ => {} + } + None + } + + #[allow(dead_code)] + fn is_artificial(&self) -> bool { + match self { + VariantInfo::Generator { .. } => true, + VariantInfo::Adt(..) => false, + } + } } /// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a @@ -1718,7 +1786,15 @@ fn describe_enum_variant( .type_map .borrow_mut() .get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name); - create_struct_stub(cx, layout.ty, &variant_name, unique_type_id, Some(containing_scope)) + create_struct_stub( + cx, + layout.ty, + &variant_name, + unique_type_id, + Some(containing_scope), + // FIXME(tmandry): This doesn't seem to have any effect. + if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero }, + ) }); // Build an array of (field name, field type) pairs to be captured in the factory closure. @@ -1778,7 +1854,13 @@ fn prepare_enum_metadata( span: Span, outer_field_tys: Vec>, ) -> RecursiveTypeDescription<'ll, 'tcx> { - let enum_name = compute_debuginfo_type_name(cx.tcx, enum_type, false); + let tcx = cx.tcx; + let enum_name = compute_debuginfo_type_name(tcx, enum_type, false); + // FIXME(tmandry): This doesn't seem to have any effect. + let enum_flags = match enum_type.kind { + ty::Generator(..) => DIFlags::FlagArtificial, + _ => DIFlags::FlagZero, + }; let containing_scope = get_namespace_for_item(cx, enum_def_id); // FIXME: This should emit actual file metadata for the enum, but we @@ -1792,7 +1874,7 @@ fn prepare_enum_metadata( let discriminant_type_metadata = |discr: Primitive| { let enumerators_metadata: Vec<_> = match enum_type.kind { ty::Adt(def, _) => def - .discriminants(cx.tcx) + .discriminants(tcx) .zip(&def.variants) .map(|((_, discr), v)| { let name = v.ident.as_str(); @@ -1815,15 +1897,16 @@ fn prepare_enum_metadata( .collect(), ty::Generator(_, substs, _) => substs .as_generator() - .variant_range(enum_def_id, cx.tcx) + .variant_range(enum_def_id, tcx) .map(|variant_index| { - let name = substs.as_generator().variant_name(variant_index); + debug_assert_eq!(tcx.types.u32, substs.as_generator().discr_ty(tcx)); + let name = GeneratorSubsts::variant_name(variant_index); unsafe { Some(llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), name.as_ptr().cast(), name.len(), - // Generators use u32 as discriminant type. + // Generators use u32 as discriminant type, verified above. variant_index.as_u32().into(), true, // IsUnsigned )) @@ -1841,12 +1924,12 @@ fn prepare_enum_metadata( None => { let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx)); let discriminant_base_type_metadata = - type_metadata(cx, discr.to_ty(cx.tcx), rustc_span::DUMMY_SP); + type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP); let item_name; let discriminant_name = match enum_type.kind { ty::Adt(..) => { - item_name = cx.tcx.item_name(enum_def_id).as_str(); + item_name = tcx.item_name(enum_def_id).as_str(); &*item_name } ty::Generator(..) => enum_name.as_str(), @@ -1912,7 +1995,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, layout.size.bits(), layout.align.abi.bits() as u32, - DIFlags::FlagZero, + enum_flags, None, 0, // RuntimeLang unique_type_id_str.as_ptr().cast(), @@ -2033,7 +2116,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, layout.size.bits(), layout.align.abi.bits() as u32, - DIFlags::FlagZero, + enum_flags, discriminator_metadata, empty_array, variant_part_unique_type_id_str.as_ptr().cast(), @@ -2059,7 +2142,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, layout.size.bits(), layout.align.abi.bits() as u32, - DIFlags::FlagZero, + enum_flags, None, type_array, 0, @@ -2110,6 +2193,7 @@ fn composite_type_metadata( composite_type_name, composite_type_unique_id, containing_scope, + DIFlags::FlagZero, ); // ... and immediately create and add the member descriptions. set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions); @@ -2211,6 +2295,7 @@ fn create_struct_stub( struct_type_name: &str, unique_type_id: UniqueTypeId, containing_scope: Option<&'ll DIScope>, + flags: DIFlags, ) -> &'ll DICompositeType { let (struct_size, struct_align) = cx.size_and_align_of(struct_type); @@ -2232,7 +2317,7 @@ fn create_struct_stub( UNKNOWN_LINE_NUMBER, struct_size.bits(), struct_align.bits() as u32, - DIFlags::FlagZero, + flags, None, empty_array, 0, diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 77009aca6d32e..5a0da6be5980e 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -70,10 +70,10 @@ fn uncached_llvm_type<'a, 'tcx>( write!(&mut name, "::{}", def.variants[index].ident).unwrap(); } } - if let (&ty::Generator(_, substs, _), &Variants::Single { index }) + if let (&ty::Generator(_, _, _), &Variants::Single { index }) = (&layout.ty.kind, &layout.variants) { - write!(&mut name, "::{}", substs.as_generator().variant_name(index)).unwrap(); + write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap(); } Some(name) } diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index 46c38840516e2..cb8b30830c5de 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -700,7 +700,7 @@ impl GrowableBitSet { /// /// All operations that involve a row and/or column index will panic if the /// index exceeds the relevant bound. -#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)] +#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)] pub struct BitMatrix { num_rows: usize, num_columns: usize, @@ -876,6 +876,22 @@ impl BitMatrix { } } +impl fmt::Debug for BitMatrix { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// Forces its contents to print in regular mode instead of alternate mode. + struct OneLinePrinter(T); + impl fmt::Debug for OneLinePrinter { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{:?}", self.0) + } + } + + write!(fmt, "BitMatrix({}x{}) ", self.num_rows, self.num_columns)?; + let items = self.rows().flat_map(|r| self.iter(r).map(move |c| (r, c))); + fmt.debug_set().entries(items.map(OneLinePrinter)).finish() + } +} + /// A fixed-column-size, variable-row-size 2D bit matrix with a moderately /// sparse representation. /// diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index 1aae97cc2a894..9ad79230a4f6d 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -10,6 +10,8 @@ use rustc_index::vec::IndexVec; use rustc_span::{Span, Symbol}; use rustc_target::abi::VariantIdx; use smallvec::SmallVec; +use std::cell::Cell; +use std::fmt::{self, Debug}; use super::{Field, SourceInfo}; @@ -58,7 +60,7 @@ rustc_index::newtype_index! { } /// The layout of generator state. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. pub field_tys: IndexVec>, @@ -67,12 +69,72 @@ pub struct GeneratorLayout<'tcx> { /// be stored in multiple variants. pub variant_fields: IndexVec>, + /// The source that led to each variant being created (usually, a yield or + /// await). + pub variant_source_info: IndexVec, + /// Which saved locals are storage-live at the same time. Locals that do not /// have conflicts with each other are allowed to overlap in the computed /// layout. pub storage_conflicts: BitMatrix, } +impl Debug for GeneratorLayout<'_> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// Prints an iterator of (key, value) tuples as a map. + struct MapPrinter<'a, K, V>(Cell + 'a>>>); + impl<'a, K, V> MapPrinter<'a, K, V> { + fn new(iter: impl Iterator + 'a) -> Self { + Self(Cell::new(Some(Box::new(iter)))) + } + } + impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().entries(self.0.take().unwrap()).finish() + } + } + + /// Prints the generator variant name. + struct GenVariantPrinter(VariantIdx); + impl From for GenVariantPrinter { + fn from(idx: VariantIdx) -> Self { + GenVariantPrinter(idx) + } + } + impl Debug for GenVariantPrinter { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let variant_name = ty::GeneratorSubsts::variant_name(self.0); + if fmt.alternate() { + write!(fmt, "{:9}({:?})", variant_name, self.0) + } else { + write!(fmt, "{}", variant_name) + } + } + } + + /// Forces its contents to print in regular mode instead of alternate mode. + struct OneLinePrinter(T); + impl Debug for OneLinePrinter { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{:?}", self.0) + } + } + + fmt.debug_struct("GeneratorLayout") + .field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated())) + .field( + "variant_fields", + &MapPrinter::new( + self.variant_fields + .iter_enumerated() + .map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))), + ), + ) + .field("storage_conflicts", &self.storage_conflicts) + .finish() + } +} + #[derive(Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 1d680c3563675..8f86d2ef522d3 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -522,8 +522,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { /// Calls `f` with a reference to the name of the enumerator for the given /// variant `v`. - #[inline] - pub fn variant_name(self, v: VariantIdx) -> Cow<'static, str> { + pub fn variant_name(v: VariantIdx) -> Cow<'static, str> { match v.as_usize() { Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME), Self::RETURNED => Cow::from(Self::RETURNED_NAME), diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 59be8dc224dee..523d3c9af3f68 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -422,6 +422,9 @@ struct LivenessInfo { /// The set of saved locals live at each suspension point. live_locals_at_suspension_points: Vec>, + /// Parallel vec to the above with SourceInfo for each yield terminator. + source_info_at_suspension_points: Vec, + /// For every saved local, the set of other saved locals that are /// storage-live at the same time as this local. We cannot overlap locals in /// the layout which have conflicting storage. @@ -473,6 +476,7 @@ fn locals_live_across_suspend_points( let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks()); let mut live_locals_at_suspension_points = Vec::new(); + let mut source_info_at_suspension_points = Vec::new(); let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len()); for (block, data) in body.basic_blocks().iter_enumerated() { @@ -518,6 +522,7 @@ fn locals_live_across_suspend_points( live_locals_at_any_suspension_point.union(&live_locals); live_locals_at_suspension_points.push(live_locals); + source_info_at_suspension_points.push(data.terminator().source_info); } } @@ -541,6 +546,7 @@ fn locals_live_across_suspend_points( LivenessInfo { saved_locals, live_locals_at_suspension_points, + source_info_at_suspension_points, storage_conflicts, storage_liveness: storage_liveness_map, } @@ -754,6 +760,7 @@ fn compute_layout<'tcx>( let LivenessInfo { saved_locals, live_locals_at_suspension_points, + source_info_at_suspension_points, storage_conflicts, storage_liveness, } = liveness; @@ -768,7 +775,18 @@ fn compute_layout<'tcx>( } // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. + // In debuginfo, these will correspond to the beginning (UNRESUMED) or end + // (RETURNED, POISONED) of the function. const RESERVED_VARIANTS: usize = 3; + let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span; + let mut variant_source_info: IndexVec = [ + SourceInfo::outermost(body_span.shrink_to_lo()), + SourceInfo::outermost(body_span.shrink_to_hi()), + SourceInfo::outermost(body_span.shrink_to_hi()), + ] + .iter() + .copied() + .collect(); // Build the generator variant field list. // Create a map from local indices to generator struct indices. @@ -787,11 +805,13 @@ fn compute_layout<'tcx>( remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx)); } variant_fields.push(fields); + variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); } debug!("generator variant_fields = {:?}", variant_fields); debug!("generator storage_conflicts = {:#?}", storage_conflicts); - let layout = GeneratorLayout { field_tys: tys, variant_fields, storage_conflicts }; + let layout = + GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; (remap, layout, storage_liveness) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 02614044063fc..db45481e4fd25 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -131,7 +131,7 @@ fn dump_matched_mir_node<'tcx, F>( } writeln!(file, " {} {}", disambiguator, pass_name)?; if let Some(ref layout) = body.generator_layout { - writeln!(file, "// generator_layout = {:?}", layout)?; + writeln!(file, "/* generator_layout = {:#?} */", layout)?; } writeln!(file)?; extra_data(PassWhere::BeforeCFG, &mut file)?; diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs new file mode 100644 index 0000000000000..4e145b81ecbf7 --- /dev/null +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -0,0 +1,48 @@ +// Verify debuginfo for generators: +// - Each variant points to the file and line of its yield point +// - The generator types and variants are marked artificial +// - Captured vars from the source are not marked artificial +// +// ignore-tidy-linelength +// compile-flags: -C debuginfo=2 --edition=2018 +// only-msvc + +async fn foo() {} +async fn async_fn_test() { + foo().await; + let s = String::from("foo"); + foo().await; +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// For brevity, we only check the struct name and members of the last variant. +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 12, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 14, +// CHECK-SAME: baseType: [[VARIANT:![0-9]*]] +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) + +fn main() { + let _dummy = async_fn_test(); +} diff --git a/src/test/codegen/async-fn-debug.rs b/src/test/codegen/async-fn-debug.rs new file mode 100644 index 0000000000000..8fa4be1ae86d8 --- /dev/null +++ b/src/test/codegen/async-fn-debug.rs @@ -0,0 +1,51 @@ +// Verify debuginfo for async fn: +// - Each variant points to the file and line of its yield point +// - The generator types and variants are marked artificial +// - Captured vars from the source are not marked artificial +// +// ignore-tidy-linelength +// compile-flags: -C debuginfo=2 --edition=2018 +// ignore-msvc + +async fn foo() {} +async fn async_fn_test() { + foo().await; + let s = String::from("foo"); + foo().await; +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial +// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK-SAME: discriminator: [[DISC:![0-9]*]] +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 12, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 14, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[ASYNC_FN]], +// CHECK-SAME: flags: DIFlagArtificial + +fn main() { + let _dummy = async_fn_test(); +} diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs new file mode 100644 index 0000000000000..82a1568ea9584 --- /dev/null +++ b/src/test/codegen/generator-debug-msvc.rs @@ -0,0 +1,52 @@ +// Verify debuginfo for generators: +// - Each variant points to the file and line of its yield point +// - The generator types and variants are marked artificial +// - Captured vars from the source are not marked artificial +// +// ignore-tidy-linelength +// compile-flags: -C debuginfo=2 +// only-msvc + +#![feature(generators, generator_trait)] +use std::ops::Generator; + +fn generator_test() -> impl Generator { + || { + yield 0; + let s = String::from("foo"); + yield 1; + } +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// For brevity, we only check the struct name and members of the last variant. +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-SAME: file: [[FILE]], line: 17, +// CHECK-SAME: baseType: [[VARIANT:![0-9]*]] +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) + +fn main() { + let _dummy = generator_test(); +} diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs new file mode 100644 index 0000000000000..5c7c64148189a --- /dev/null +++ b/src/test/codegen/generator-debug.rs @@ -0,0 +1,55 @@ +// Verify debuginfo for generators: +// - Each variant points to the file and line of its yield point +// - The generator types and variants are marked artificial +// - Captured vars from the source are not marked artificial +// +// ignore-tidy-linelength +// compile-flags: -C debuginfo=2 --edition=2018 +// ignore-msvc + +#![feature(generators, generator_trait)] +use std::ops::Generator; + +fn generator_test() -> impl Generator { + || { + yield 0; + let s = String::from("foo"); + yield 1; + } +} + +// FIXME: No way to reliably check the filename. + +// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial +// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK-SAME: discriminator: [[DISC:![0-9]*]] +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 15, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], +// CHECK-SAME: file: [[FILE]], line: 17, +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], +// CHECK-SAME: flags: DIFlagArtificial +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) +// CHECK: [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN_FN]], +// CHECK-SAME: flags: DIFlagArtificial + +fn main() { + let _dummy = generator_test(); +} diff --git a/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir b/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir index 3e7083ff62ecd..3c77995eea893 100644 --- a/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir +++ b/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir @@ -1,5 +1,18 @@ // MIR for `main::{{closure}}#0` 0 generator_drop -// generator_layout = GeneratorLayout { field_tys: [std::string::String], variant_fields: [[], [], [], [_0]], storage_conflicts: BitMatrix { num_rows: 1, num_columns: 1, words: [1], marker: PhantomData } } +/* generator_layout = GeneratorLayout { + field_tys: { + _0: std::string::String, + }, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + Suspend0 (3): [_0], + }, + storage_conflicts: BitMatrix(1x1) { + (_0, _0), + }, +} */ fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {std::string::String, ()}]) -> () { let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 diff --git a/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir b/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir index c73dea5f8fde6..bd6db11a7e73e 100644 --- a/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir +++ b/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir @@ -1,5 +1,18 @@ // MIR for `main::{{closure}}#0` 0 generator_resume -// generator_layout = GeneratorLayout { field_tys: [HasDrop], variant_fields: [[], [], [], [_0]], storage_conflicts: BitMatrix { num_rows: 1, num_columns: 1, words: [1], marker: PhantomData } } +/* generator_layout = GeneratorLayout { + field_tys: { + _0: HasDrop, + }, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + Suspend0 (3): [_0], + }, + storage_conflicts: BitMatrix(1x1) { + (_0, _0), + }, +} */ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> std::ops::GeneratorState<(), ()> { debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19