debuginfo: Make sure that type names for closure and generator environments are unique in debuginfo.

Before this change, closure/generator environments coming from different
instantiations of the same generic function were all assigned the same
name even though they were distinct types with potentially different data
layout. Now we append the generic arguments of the originating function
to the type name.

This commit also emits '{closure_env#0}' as the name of these types in
order to disambiguate them from the accompanying closure function
'{closure#0}'. Previously both were assigned the same name.
This commit is contained in:
Michael Woerister 2022-01-19 17:56:53 +01:00
parent 0bcacb391b
commit fd7557b7ee
14 changed files with 287 additions and 121 deletions

View File

@ -25,7 +25,7 @@ use rustc_data_structures::sync::Lrc;
use rustc_hir::def_id::{DefId, DefIdMap};
use rustc_index::vec::IndexVec;
use rustc_middle::mir;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
use rustc_session::config::{self, DebugInfo};
@ -307,9 +307,11 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
maybe_definition_llfn: Option<&'ll Value>,
) -> &'ll DIScope {
let tcx = self.tcx;
let def_id = instance.def_id();
let containing_scope = get_containing_scope(self, instance);
let span = self.tcx.def_span(def_id);
let span = tcx.def_span(def_id);
let loc = self.lookup_debug_loc(span.lo());
let file_metadata = file_metadata(self, &loc.file);
@ -319,16 +321,24 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
};
let mut name = String::new();
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
type_names::push_item_name(tcx, def_id, false, &mut name);
// Find the enclosing function, in case this is a closure.
let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
let generics = self.tcx().generics_of(enclosing_fn_def_id);
let substs = instance.substs.truncate_to(self.tcx(), generics);
let template_parameters = get_template_parameters(self, generics, substs, &mut name);
// We look up the generics of the enclosing function and truncate the substs
// to their length in order to cut off extra stuff that might be in there for
// closures or generators.
let generics = tcx.generics_of(enclosing_fn_def_id);
let substs = instance.substs.truncate_to(tcx, generics);
type_names::push_generic_params(
tcx,
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs),
&mut name,
);
let template_parameters = get_template_parameters(self, generics, substs);
let linkage_name = &mangled_name_of_instance(self, instance).name;
// Omit the linkage_name if it is the same as subprogram name.
@ -350,7 +360,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
if self.sess().opts.optimize != config::OptLevel::No {
spflags |= DISPFlags::SPFlagOptimized;
}
if let Some((id, _)) = self.tcx.entry_fn(()) {
if let Some((id, _)) = tcx.entry_fn(()) {
if id == def_id {
spflags |= DISPFlags::SPFlagMainSubprogram;
}
@ -429,14 +439,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
cx: &CodegenCx<'ll, 'tcx>,
generics: &ty::Generics,
substs: SubstsRef<'tcx>,
name_to_append_suffix_to: &mut String,
) -> &'ll DIArray {
type_names::push_generic_params(
cx.tcx,
cx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs),
name_to_append_suffix_to,
);
if substs.types().next().is_none() {
return create_DIArray(DIB(cx), &[]);
}

View File

@ -13,9 +13,9 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, AdtDef, ExistentialProjection, Ty, TyCtxt};
@ -102,14 +102,14 @@ fn push_debuginfo_type_name<'tcx>(
ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
if cpp_like_debuginfo {
match mutbl {
hir::Mutability::Not => output.push_str("ptr_const$<"),
hir::Mutability::Mut => output.push_str("ptr_mut$<"),
Mutability::Not => output.push_str("ptr_const$<"),
Mutability::Mut => output.push_str("ptr_mut$<"),
}
} else {
output.push('*');
match mutbl {
hir::Mutability::Not => output.push_str("const "),
hir::Mutability::Mut => output.push_str("mut "),
Mutability::Not => output.push_str("const "),
Mutability::Mut => output.push_str("mut "),
}
}
@ -131,8 +131,8 @@ fn push_debuginfo_type_name<'tcx>(
output.push_str(mutbl.prefix_str());
} else if !is_slice_or_str {
match mutbl {
hir::Mutability::Not => output.push_str("ref$<"),
hir::Mutability::Mut => output.push_str("ref_mut$<"),
Mutability::Not => output.push_str("ref$<"),
Mutability::Mut => output.push_str("ref_mut$<"),
}
}
@ -345,14 +345,39 @@ fn push_debuginfo_type_name<'tcx>(
// processing
visited.remove(t);
}
ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
let key = tcx.def_key(def_id);
ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
// Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
// "{async_fn_env#0}<T1, T2, ...>", etc.
let def_key = tcx.def_key(def_id);
if qualified {
let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
push_item_name(tcx, parent_def_id, true, output);
output.push_str("::");
}
push_unqualified_item_name(tcx, def_id, key.disambiguated_data, output);
let mut label = String::with_capacity(20);
write!(&mut label, "{}_env", generator_kind_label(tcx.generator_kind(def_id))).unwrap();
push_disambiguated_special_name(
&label,
def_key.disambiguated_data.disambiguator,
cpp_like_debuginfo,
output,
);
// We also need to add the generic arguments of the async fn/generator or
// the enclosing function (for closures or async blocks), so that we end
// up with a unique name for every instantiation.
// Find the generics of the enclosing function, as defined in the source code.
let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
let generics = tcx.generics_of(enclosing_fn_def_id);
// Truncate the substs to the length of the above generics. This will cut off
// anything closure- or generator-specific.
let substs = substs.truncate_to(tcx, generics);
push_generic_params_internal(tcx, substs, output, visited);
}
// Type parameters from polymorphized functions.
ty::Param(_) => {
@ -509,6 +534,29 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &
push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
}
fn generator_kind_label(generator_kind: Option<GeneratorKind>) -> &'static str {
match generator_kind {
Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) => "async_block",
Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) => "async_closure",
Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) => "async_fn",
Some(GeneratorKind::Gen) => "generator",
None => "closure",
}
}
fn push_disambiguated_special_name(
label: &str,
disambiguator: u32,
cpp_like_debuginfo: bool,
output: &mut String,
) {
if cpp_like_debuginfo {
write!(output, "{}${}", label, disambiguator).unwrap();
} else {
write!(output, "{{{}#{}}}", label, disambiguator).unwrap();
}
}
fn push_unqualified_item_name(
tcx: TyCtxt<'_>,
def_id: DefId,
@ -519,42 +567,32 @@ fn push_unqualified_item_name(
DefPathData::CrateRoot => {
output.push_str(tcx.crate_name(def_id.krate).as_str());
}
DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
let key = match tcx.generator_kind(def_id).unwrap() {
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block",
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure",
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn",
hir::GeneratorKind::Gen => "generator",
};
// Generators look like closures, but we want to treat them differently
// in the debug info.
if cpp_like_debuginfo(tcx) {
write!(output, "{}${}", key, disambiguated_data.disambiguator).unwrap();
} else {
write!(output, "{{{}#{}}}", key, disambiguated_data.disambiguator).unwrap();
}
DefPathData::ClosureExpr => {
let label = generator_kind_label(tcx.generator_kind(def_id));
push_disambiguated_special_name(
label,
disambiguated_data.disambiguator,
cpp_like_debuginfo(tcx),
output,
);
}
_ => match disambiguated_data.data.name() {
DefPathDataName::Named(name) => {
output.push_str(name.as_str());
}
DefPathDataName::Anon { namespace } => {
if cpp_like_debuginfo(tcx) {
write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap();
} else {
write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)
.unwrap();
}
push_disambiguated_special_name(
namespace.as_str(),
disambiguated_data.disambiguator,
cpp_like_debuginfo(tcx),
output,
);
}
},
};
}
// Pushes the generic parameters in the given `InternalSubsts` to the output string.
// This ignores region parameters, since they can't reliably be
// reconstructed for items from non-local crates. For local crates, this
// would be possible but with inlining and LTO we have to use the least
// common denominator - otherwise we would run into conflicts.
fn push_generic_params_internal<'tcx>(
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,

View File

@ -17,7 +17,7 @@ async fn async_fn_test() {
// 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: "async_fn$0"
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "async_fn_env$0"
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
// For brevity, we only check the struct name and members of the last variant.
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,

View File

@ -17,7 +17,7 @@ async fn async_fn_test() {
// 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: "{async_fn#0}", scope: [[ASYNC_FN]]
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[ASYNC_FN]]
// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: discriminator: [[DISC:![0-9]*]]

View File

@ -1,25 +1,36 @@
// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Ccodegen-units=1
// ignore-tidy-linelength
// This test checks the debuginfo for the expected 3 vtables is generated for correct names and number
// of entries.
// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable$"
// Use the v0 symbol mangling scheme to codegen order independent of rustc version.
// Unnamed items like shims are generated in lexicographical order of their symbol name and in the
// legacy mangling scheme rustc version and generic parameters are both hashed into a single part
// of the name, thus randomizing item order with respect to rustc version.
// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
// ignore-tidy-linelength
// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable$"
// NONMSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()",
// MSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >",
// CHECK: !DISubrange(count: 5
// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable$"
// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable$"
// CHECK: !DISubrange(count: 4
// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as _>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as _>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
// CHECK: !DISubrange(count: 3
// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::bar::{closure#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure$0, core::ops::function::FnOnce<tuple$<enum$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$"
// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::bar::{closure_env#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure_env$0, core::ops::function::FnOnce<tuple$<enum$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$"
// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::generic_closure::{closure_env#0}<bool> as core::ops::function::FnOnce<()>>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::generic_closure::closure_env$0<bool>, core::ops::function::FnOnce<tuple$<> > >::vtable$
// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::generic_closure::{closure_env#0}<u32> as core::ops::function::FnOnce<()>>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::generic_closure::closure_env$0<u32>, core::ops::function::FnOnce<tuple$<> > >::vtable$
#![crate_type = "lib"]
@ -31,8 +42,12 @@ pub trait SomeTrait {
}
impl SomeTrait for Foo {
fn method1(&self) -> u32 { 1 }
fn method2(&self) -> u32 { 2 }
fn method1(&self) -> u32 {
1
}
fn method2(&self) -> u32 {
2
}
}
pub trait SomeTraitWithGenerics<T, U> {
@ -40,7 +55,9 @@ pub trait SomeTraitWithGenerics<T, U> {
}
impl SomeTraitWithGenerics<u64, i8> for Foo {
fn method1(&self) -> (u64, i8) { (1, 2) }
fn method1(&self) -> (u64, i8) {
(1, 2)
}
}
pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) {
@ -55,3 +72,11 @@ pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) {
pub fn bar() -> Box<dyn FnOnce(Option<&dyn Fn()>)> {
Box::new(|_x: Option<&dyn Fn()>| {})
}
fn generic_closure<T: 'static>(x: T) -> Box<dyn FnOnce() -> T> {
Box::new(move || x)
}
pub fn instantiate_generic_closures() -> (Box<dyn FnOnce() -> u32>, Box<dyn FnOnce() -> bool>) {
(generic_closure(1u32), generic_closure(false))
}

View File

@ -0,0 +1,91 @@
// This test checks that we get proper type names for closure environments and
// async-fn environments in debuginfo, especially making sure that generic arguments
// of the enclosing functions don't get lost.
//
// Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard
// to predict once async fns are involved.
//
// Note that the test does not check async-fns when targeting MSVC because debuginfo for
// those does not follow the enum-fallback encoding yet and thus is incomplete.
// ignore-tidy-linelength
// Use the v0 symbol mangling scheme to codegen order independent of rustc version.
// Unnamed items like shims are generated in lexicographical order of their symbol name and in the
// legacy mangling scheme rustc version and generic parameters are both hashed into a single part
// of the name, thus randomizing item order with respect to rustc version.
// compile-flags: -Cdebuginfo=2 --edition 2021 -Copt-level=0 -Csymbol-mangling-version=v0
// CHECK: [[non_generic_closure_NAMESPACE:!.*]] = !DINamespace(name: "non_generic_closure"
// CHECK: [[function_containing_closure_NAMESPACE:!.*]] = !DINamespace(name: "function_containing_closure"
// CHECK: [[generic_async_function_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_function"
// CHECK: [[generic_async_block_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_block"
// non_generic_closure()
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[non_generic_closure_NAMESPACE]]
// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[non_generic_closure_NAMESPACE]]
// function_containing_closure<u32>()
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<u32>", scope: [[function_containing_closure_NAMESPACE]]
// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<u32>", scope: [[function_containing_closure_NAMESPACE]]
// generic_async_function<Foo>()
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: [[generic_async_function_NAMESPACE]]
// generic_async_function<u32>()
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<u32>", scope: [[generic_async_function_NAMESPACE]]
// generic_async_block<Foo>()
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: [[generic_async_block_NAMESPACE]]
// generic_async_block<u32>()
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<u32>", scope: [[generic_async_block_NAMESPACE]]
// function_containing_closure<Foo>()
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: [[function_containing_closure_NAMESPACE]]
// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<debuginfo_generic_closure_env_names::Foo>", scope: [[function_containing_closure_NAMESPACE]]
#![crate_type = "lib"]
use std::future::Future;
pub struct Foo;
pub fn non_generic_closure(x: Foo) -> Box<dyn FnOnce() -> Foo> {
// This static only exists to trigger generating the namespace debuginfo for
// `function_containing_closure` at a predictable, early point, which makes
// writing the FileCheck tests above simpler.
static _X: u8 = 0;
return Box::new(move || x);
}
fn function_containing_closure<T: 'static>(x: T) -> impl FnOnce() -> T {
static _X: u8 = 0; // Same as above
return move || x;
}
async fn generic_async_function<T: 'static>(x: T) -> T {
static _X: u8 = 0; // Same as above
x
}
fn generic_async_block<T: 'static>(x: T) -> impl Future<Output=T> {
static _X: u8 = 0; // Same as above
async move {
x
}
}
pub fn instantiate_generics() {
let _closure_u32 = function_containing_closure(7u32);
let _closure_foo = function_containing_closure(Foo);
let _async_fn_u32 = generic_async_function(42u32);
let _async_fn_foo = generic_async_function(Foo);
let _async_block_u32 = generic_async_block(64u32);
let _async_block_foo = generic_async_block(Foo);
}

View File

@ -21,7 +21,7 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
// 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"
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator_env$0"
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
// For brevity, we only check the struct name and members of the last variant.
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,

View File

@ -21,7 +21,7 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
// 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]]
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator_env#0}", scope: [[GEN_FN]]
// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]],
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: discriminator: [[DISC:![0-9]*]]

View File

@ -4,44 +4,44 @@
// gdb-command:run
// gdb-command:print test
// gdbr-check:$1 = captured_fields_1::main::{closure#0} {_ref__my_ref__my_field1: 0x[...]}
// gdbr-check:$1 = captured_fields_1::main::{closure_env#0} {_ref__my_ref__my_field1: 0x[...]}
// gdb-command:continue
// gdb-command:print test
// gdbr-check:$2 = captured_fields_1::main::{closure#1} {_ref__my_ref__my_field2: 0x[...]}
// gdbr-check:$2 = captured_fields_1::main::{closure_env#1} {_ref__my_ref__my_field2: 0x[...]}
// gdb-command:continue
// gdb-command:print test
// gdbr-check:$3 = captured_fields_1::main::{closure#2} {_ref__my_ref: 0x[...]}
// gdbr-check:$3 = captured_fields_1::main::{closure_env#2} {_ref__my_ref: 0x[...]}
// gdb-command:continue
// gdb-command:print test
// gdbr-check:$4 = captured_fields_1::main::{closure#3} {my_ref: 0x[...]}
// gdbr-check:$4 = captured_fields_1::main::{closure_env#3} {my_ref: 0x[...]}
// gdb-command:continue
// gdb-command:print test
// gdbr-check:$5 = captured_fields_1::main::{closure#4} {my_var__my_field2: 22}
// gdbr-check:$5 = captured_fields_1::main::{closure_env#4} {my_var__my_field2: 22}
// gdb-command:continue
// gdb-command:print test
// gdbr-check:$6 = captured_fields_1::main::{closure#5} {my_var: captured_fields_1::MyStruct {my_field1: 11, my_field2: 22}}
// gdbr-check:$6 = captured_fields_1::main::{closure_env#5} {my_var: captured_fields_1::MyStruct {my_field1: 11, my_field2: 22}}
// gdb-command:continue
// === LLDB TESTS ==================================================================================
// lldb-command:run
// lldb-command:print test
// lldbg-check:(captured_fields_1::main::{closure#0}) $0 = { _ref__my_ref__my_field1 = 0x[...] }
// lldbg-check:(captured_fields_1::main::{closure_env#0}) $0 = { _ref__my_ref__my_field1 = 0x[...] }
// lldb-command:continue
// lldb-command:print test
// lldbg-check:(captured_fields_1::main::{closure#1}) $1 = { _ref__my_ref__my_field2 = 0x[...] }
// lldbg-check:(captured_fields_1::main::{closure_env#1}) $1 = { _ref__my_ref__my_field2 = 0x[...] }
// lldb-command:continue
// lldb-command:print test
// lldbg-check:(captured_fields_1::main::{closure#2}) $2 = { _ref__my_ref = 0x[...] }
// lldbg-check:(captured_fields_1::main::{closure_env#2}) $2 = { _ref__my_ref = 0x[...] }
// lldb-command:continue
// lldb-command:print test
// lldbg-check:(captured_fields_1::main::{closure#3}) $3 = { my_ref = 0x[...] }
// lldbg-check:(captured_fields_1::main::{closure_env#3}) $3 = { my_ref = 0x[...] }
// lldb-command:continue
// lldb-command:print test
// lldbg-check:(captured_fields_1::main::{closure#4}) $4 = { my_var__my_field2 = 22 }
// lldbg-check:(captured_fields_1::main::{closure_env#4}) $4 = { my_var__my_field2 = 22 }
// lldb-command:continue
// lldb-command:print test
// lldbg-check:(captured_fields_1::main::{closure#5}) $5 = { my_var = { my_field1 = 11 my_field2 = 22 } }
// lldbg-check:(captured_fields_1::main::{closure_env#5}) $5 = { my_var = { my_field1 = 11 my_field2 = 22 } }
// lldb-command:continue
#![feature(capture_disjoint_fields)]
@ -53,10 +53,7 @@ struct MyStruct {
}
fn main() {
let mut my_var = MyStruct {
my_field1: 11,
my_field2: 22,
};
let mut my_var = MyStruct { my_field1: 11, my_field2: 22 };
let my_ref = &mut my_var;
let test = || {

View File

@ -27,9 +27,9 @@
// Closure
// gdb-command:info functions -q function_names::.*::{closure.*
// gdb-check:[...]static fn function_names::generic_func::{closure#0}<i32>(*mut function_names::generic_func::{closure#0});
// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure#0});
// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}<i32, i32>(*mut function_names::{impl#2}::impl_function::{closure#0});
// gdb-check:[...]static fn function_names::generic_func::{closure#0}<i32>(*mut function_names::generic_func::{closure_env#0}<i32>);
// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure_env#0});
// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}<i32, i32>(*mut function_names::{impl#2}::impl_function::{closure_env#0}<i32, i32>);
// Generator
// Generators don't seem to appear in GDB's symbol table.
@ -86,9 +86,9 @@
#![feature(adt_const_params, generators, generator_trait)]
#![allow(incomplete_features)]
use Mod1::TestTrait2;
use std::ops::Generator;
use std::pin::Pin;
use Mod1::TestTrait2;
fn main() {
// Implementations
@ -107,16 +107,19 @@ fn main() {
let _ = generic_func(42i32);
// Closure
let closure = || { TestStruct1 };
let closure = || TestStruct1;
closure();
// Generator
let mut generator = || { yield; return; };
let mut generator = || {
yield;
return;
};
Pin::new(&mut generator).resume(());
// Const generic functions
const_generic_fn_bool::<false>();
const_generic_fn_non_int::<{()}>();
const_generic_fn_non_int::<{ () }>();
const_generic_fn_signed_int::<-7>();
const_generic_fn_unsigned_int::<14>();
}
@ -158,7 +161,7 @@ struct GenericStruct<T1, T2>(std::marker::PhantomData<(T1, T2)>);
impl<T1, T2> GenericStruct<T1, T2> {
pub fn impl_function() {
// Closure in a generic implementation
let closure = || { TestStruct1 };
let closure = || TestStruct1;
closure();
}
}
@ -190,7 +193,7 @@ impl<T, const N: usize> TestTrait1 for GenericStruct<[T; N], f32> {
// Generic function
fn generic_func<T>(value: T) -> T {
// Closure in a generic function
let closure = || { TestStruct1 };
let closure = || TestStruct1;
closure();
value

View File

@ -11,31 +11,31 @@
// gdb-command:run
// gdb-command:print b
// gdb-check:$1 = generator_objects::main::{generator#0}::Unresumed{_ref__a: 0x[...]}
// gdb-check:$1 = generator_objects::main::{generator_env#0}::Unresumed{_ref__a: 0x[...]}
// gdb-command:continue
// gdb-command:print b
// gdb-check:$2 = generator_objects::main::{generator#0}::Suspend0{c: 6, d: 7, _ref__a: 0x[...]}
// gdb-check:$2 = generator_objects::main::{generator_env#0}::Suspend0{c: 6, d: 7, _ref__a: 0x[...]}
// gdb-command:continue
// gdb-command:print b
// gdb-check:$3 = generator_objects::main::{generator#0}::Suspend1{c: 7, d: 8, _ref__a: 0x[...]}
// gdb-check:$3 = generator_objects::main::{generator_env#0}::Suspend1{c: 7, d: 8, _ref__a: 0x[...]}
// gdb-command:continue
// gdb-command:print b
// gdb-check:$4 = generator_objects::main::{generator#0}::Returned{_ref__a: 0x[...]}
// gdb-check:$4 = generator_objects::main::{generator_env#0}::Returned{_ref__a: 0x[...]}
// === LLDB TESTS ==================================================================================
// lldb-command:run
// lldb-command:print b
// lldbg-check:(generator_objects::main::{generator#0}) $0 =
// lldbg-check:(generator_objects::main::{generator_env#0}) $0 =
// lldb-command:continue
// lldb-command:print b
// lldbg-check:(generator_objects::main::{generator#0}) $1 =
// lldbg-check:(generator_objects::main::{generator_env#0}) $1 =
// lldb-command:continue
// lldb-command:print b
// lldbg-check:(generator_objects::main::{generator#0}) $2 =
// lldbg-check:(generator_objects::main::{generator_env#0}) $2 =
// lldb-command:continue
// lldb-command:print b
// lldbg-check:(generator_objects::main::{generator#0}) $3 =
// lldbg-check:(generator_objects::main::{generator_env#0}) $3 =
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
#![omit_gdb_pretty_printer_section]
@ -66,4 +66,6 @@ fn main() {
_zzz(); // #break
}
fn _zzz() {()}
fn _zzz() {
()
}

View File

@ -11,20 +11,20 @@
// gdb-command:run
// gdb-command:print g
// gdb-check:$1 = issue_57822::main::{closure#1} {f: issue_57822::main::{closure#0} {x: 1}}
// gdb-check:$1 = issue_57822::main::{closure_env#1} {f: issue_57822::main::{closure_env#0} {x: 1}}
// gdb-command:print b
// gdb-check:$2 = issue_57822::main::{generator#3}::Unresumed{a: issue_57822::main::{generator#2}::Unresumed{y: 2}}
// gdb-check:$2 = issue_57822::main::{generator_env#3}::Unresumed{a: issue_57822::main::{generator_env#2}::Unresumed{y: 2}}
// === LLDB TESTS ==================================================================================
// lldb-command:run
// lldb-command:print g
// lldbg-check:(issue_57822::main::{closure#1}) $0 = { f = { x = 1 } }
// lldbg-check:(issue_57822::main::{closure_env#1}) $0 = { f = { x = 1 } }
// lldb-command:print b
// lldbg-check:(issue_57822::main::{generator#3}) $1 =
// lldbg-check:(issue_57822::main::{generator_env#3}) $1 =
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
#![omit_gdb_pretty_printer_section]
@ -50,4 +50,6 @@ fn main() {
zzz(); // #break
}
fn zzz() { () }
fn zzz() {
()
}

View File

@ -122,7 +122,6 @@
// gdb-command:whatis has_associated_type_trait
// gdb-check:type = &(dyn type_names::Trait3<u32, AssocType=isize> + core::marker::Send)
// BARE FUNCTIONS
// gdb-command:whatis rust_fn
// gdb-check:type = (fn(core::option::Option<isize>, core::option::Option<&type_names::mod1::Struct2>), usize)
@ -153,10 +152,10 @@
// CLOSURES
// gdb-command:whatis closure1
// gdb-check:type = (type_names::main::{closure#0}, usize)
// gdb-check:type = (type_names::main::{closure_env#0}, usize)
// gdb-command:whatis closure2
// gdb-check:type = (type_names::main::{closure#1}, usize)
// gdb-check:type = (type_names::main::{closure_env#1}, usize)
// FOREIGN TYPES
// gdb-command:whatis foreign1
@ -254,8 +253,8 @@
// CLOSURES
// cdb-command:dv /t closure*
// cdb-check:struct tuple$<type_names::main::closure$1,usize> closure2 = [...]
// cdb-check:struct tuple$<type_names::main::closure$0,usize> closure1 = [...]
// cdb-check:struct tuple$<type_names::main::closure_env$1,usize> closure2 = [...]
// cdb-check:struct tuple$<type_names::main::closure_env$0,usize> closure1 = [...]
// FOREIGN TYPES
// cdb-command:dv /t foreign*
@ -279,7 +278,9 @@ enum Enum1 {
Variant2(isize),
}
extern { type ForeignType1; }
extern "C" {
type ForeignType1;
}
mod mod1 {
pub use self::Enum2::{Variant1, Variant2};
@ -300,7 +301,9 @@ mod mod1 {
}
}
extern { pub type ForeignType2; }
extern "C" {
pub type ForeignType2;
}
}
trait Trait1 {
@ -311,7 +314,9 @@ trait Trait2<T1, T2> {
}
trait Trait3<T> {
type AssocType;
fn dummy(&self) -> T { panic!() }
fn dummy(&self) -> T {
panic!()
}
}
impl Trait1 for isize {}
@ -441,8 +446,8 @@ fn main() {
let closure2 = (|x: i8, y: f32| (x as f32) + y, 0_usize);
// Foreign Types
let foreign1 = unsafe{ 0 as *const ForeignType1 };
let foreign2 = unsafe{ 0 as *const mod1::ForeignType2 };
let foreign1 = unsafe { 0 as *const ForeignType1 };
let foreign2 = unsafe { 0 as *const mod1::ForeignType2 };
zzz(); // #break
}

View File

@ -108,7 +108,7 @@
// cdb-command: dx closure_local
// cdb-check:closure_local : 8 [Type: [...]]
// cdb-command: dx nested_closure
// cdb-check:nested_closure [Type: var_captured_in_nested_closure::main::closure$0::closure$0]
// cdb-check:nested_closure [Type: var_captured_in_nested_closure::main::closure$0::closure_env$0]
// cdb-command: g