Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-variant layouts for generators #59897

Merged
merged 13 commits into from
May 4, 2019
Merged
2 changes: 1 addition & 1 deletion src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -2997,7 +2997,7 @@ pub struct UnsafetyCheckResult {
/// The layout of generator state
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
pub struct GeneratorLayout<'tcx> {
pub variant_fields: Vec<Vec<LocalDecl<'tcx>>>,
pub variant_fields: IndexVec<VariantIdx, Vec<LocalDecl<'tcx>>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the inner Vec could be IndexVec<Field.
Also, surprised this is LocalDecl, is that only for debuginfo?
If so, can you add something similar to __upvar_debuginfo_codegen_only_do_not_use, to ensure there is no cross-talk between debuginfo and non-debuginfo usecases?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, no, we also use it to get the type of the fields in GeneratorSubsts::state_tys(). I suppose I can turn it into a struct with something like __upvar_debuginfo_codegen_only_do_not_use and whatever struct we should be using here. (What should we be using? Right now we only need the type, I think.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant that GeneratorLayout should only have Ty<'tcx>, and that debuginfo should be separate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I separated these out and made a GeneratorField newtype. That way our layout code will also know when the same field is in two variants so it can lay them out correctly (see the FIXME I added).

}

#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
25 changes: 17 additions & 8 deletions src/librustc_codegen_llvm/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ use rustc::hir::def::CtorKind;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::ich::NodeIdHashingMode;
use rustc::mir::Field;
use rustc::mir::GeneratorLayout;
use rustc::mir::interpret::truncate;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc::ty::Instance;
@@ -1291,7 +1292,10 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
let variant_info_for = |index: VariantIdx| {
match &self.enum_type.sty {
ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
ty::Generator(_, substs, _) => VariantInfo::Generator(*substs, index),
ty::Generator(def_id, substs, _) => {
let generator_layout = cx.tcx.generator_layout(*def_id);
VariantInfo::Generator(*substs, generator_layout, index)
}
_ => bug!(),
}
};
@@ -1567,22 +1571,22 @@ enum EnumDiscriminantInfo<'ll> {
#[derive(Copy, Clone)]
enum VariantInfo<'tcx> {
Adt(&'tcx ty::VariantDef),
Generator(ty::GeneratorSubsts<'tcx>, VariantIdx),
Generator(ty::GeneratorSubsts<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx),
}

impl<'tcx> VariantInfo<'tcx> {
fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
match self {
VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
VariantInfo::Generator(substs, variant_index) =>
VariantInfo::Generator(substs, _, variant_index) =>
substs.map_variant_name(*variant_index, f),
}
}

fn variant_name(&self) -> String {
match self {
VariantInfo::Adt(variant) => variant.ident.to_string(),
VariantInfo::Generator(_, variant_index) => {
VariantInfo::Generator(_, _, variant_index) => {
// Since GDB currently prints out the raw discriminant along
// with every variant, make each variant name be just the value
// of the discriminant. The struct name for the variant includes
@@ -1593,11 +1597,16 @@ impl<'tcx> VariantInfo<'tcx> {
}

fn field_name(&self, i: usize) -> String {
match self {
let field_name = match self {
VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn =>
variant.fields[i].ident.to_string(),
_ => format!("__{}", i),
}
Some(variant.fields[i].ident.to_string()),
VariantInfo::Generator(_, generator_layout, variant_index) => {
let variant_decls = &generator_layout.variant_fields[*variant_index];
variant_decls[i].name.map(|name| name.to_string())
}
_ => None,
};
field_name.unwrap_or_else(|| format!("__{}", i))
}
}

8 changes: 4 additions & 4 deletions src/test/debuginfo/generator-objects.rs
Original file line number Diff line number Diff line change
@@ -10,16 +10,16 @@

// gdb-command:run
// gdb-command:print b
// gdb-check:$1 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 0, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 ([...]), 4: generator_objects::main::generator::variant#4 ([...])}}
// gdb-check:$1 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 0, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 {[...]}, 4: generator_objects::main::generator::variant#4 {[...]}}}
// gdb-command:continue
// gdb-command:print b
// gdb-check:$2 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 3, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 (6, 7), 4: generator_objects::main::generator::variant#4 ([...])}}
// gdb-check:$2 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 3, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 {c: 6, d: 7}, 4: generator_objects::main::generator::variant#4 {[...]}}}
// gdb-command:continue
// gdb-command:print b
// gdb-check:$3 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 4, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 ([...]), 4: generator_objects::main::generator::variant#4 (7, 8)}}
// gdb-check:$3 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 4, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 {[...]}, 4: generator_objects::main::generator::variant#4 {c: 7, d: 8}}}
// gdb-command:continue
// gdb-command:print b
// gdb-check:$4 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 1, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 ([...]), 4: generator_objects::main::generator::variant#4 ([...])}}
// gdb-check:$4 = generator_objects::main::generator {__0: 0x[...], <<variant>>: {__state: 1, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::variant#3 {[...]}, 4: generator_objects::main::generator::variant#4 {[...]}}}

// === LLDB TESTS ==================================================================================