Improve debug symbol names to avoid ambiguity and work better with MSVC's debugger
There are several cases where names of types and functions in the debug info are either ambiguous, or not helpful, such as including ambiguous placeholders (e.g., `{{impl}}`, `{{closure}}` or `dyn _'`) or dropping qualifications (e.g., for dynamic types). Instead, each debug symbol name should be unique and useful: * Include disambiguators for anonymous `DefPathDataName` (closures and generators), and unify their formatting when used as a path-qualifier vs item being qualified. * Qualify the principal trait for dynamic types. * If there is no principal trait for a dynamic type, emit all other traits instead. * Respect the `qualified` argument when emitting ref and pointer types. * For implementations, emit the disambiguator. * Print const generics when emitting generic parameters or arguments. Additionally, when targeting MSVC, its debugger treats many command arguments as C++ expressions, even when the argument is defined to be a symbol name. As such names in the debug info need to be more C++-like to be parsed correctly: * Avoid characters with special meaning (`#`, `[`, `"`, `+`). * Never start a name with `<` or `{` as this is treated as an operator. * `>>` is always treated as a right-shift, even when parsing generic arguments (so add a space to avoid this). * Emit function declarations using C/C++ style syntax (e.g., leading return type). * Emit arrays as a synthetic `array$<type, size>` type. * Include a `$` in all synthetic types as this is a legal character for C++, but not Rust (thus we avoid collisions with user types).
This commit is contained in:
parent
868c702d0c
commit
aac8a88552
29 changed files with 855 additions and 357 deletions
|
@ -471,21 +471,28 @@ fn trait_pointer_metadata(
|
|||
// type is assigned the correct name, size, namespace, and source location.
|
||||
// However, it does not describe the trait's methods.
|
||||
|
||||
let containing_scope = match trait_type.kind() {
|
||||
ty::Dynamic(ref data, ..) => {
|
||||
data.principal_def_id().map(|did| get_namespace_for_item(cx, did))
|
||||
}
|
||||
_ => {
|
||||
bug!(
|
||||
"debuginfo: unexpected trait-object type in \
|
||||
trait_pointer_metadata(): {:?}",
|
||||
trait_type
|
||||
);
|
||||
}
|
||||
};
|
||||
let (containing_scope, trait_type_name) = match trait_object_type {
|
||||
Some(trait_object_type) => match trait_object_type.kind() {
|
||||
ty::Adt(def, _) => (
|
||||
Some(get_namespace_for_item(cx, def.did)),
|
||||
compute_debuginfo_type_name(cx.tcx, trait_object_type, false),
|
||||
),
|
||||
ty::RawPtr(_) | ty::Ref(..) => {
|
||||
(NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true))
|
||||
}
|
||||
_ => {
|
||||
bug!(
|
||||
"debuginfo: unexpected trait-object type in \
|
||||
trait_pointer_metadata(): {:?}",
|
||||
trait_object_type
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
let trait_object_type = trait_object_type.unwrap_or(trait_type);
|
||||
let trait_type_name = compute_debuginfo_type_name(cx.tcx, trait_object_type, false);
|
||||
// No object type, use the trait type directly (no scope here since the type
|
||||
// will be wrapped in the dyn$ synthetic type).
|
||||
None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
|
||||
};
|
||||
|
||||
let file_metadata = unknown_file_metadata(cx);
|
||||
|
||||
|
@ -525,7 +532,7 @@ fn trait_pointer_metadata(
|
|||
|
||||
composite_type_metadata(
|
||||
cx,
|
||||
trait_object_type,
|
||||
trait_object_type.unwrap_or(trait_type),
|
||||
&trait_type_name[..],
|
||||
unique_type_id,
|
||||
member_descriptions,
|
||||
|
|
|
@ -5,7 +5,6 @@ use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
|
|||
use self::metadata::{file_metadata, type_metadata, TypeMap};
|
||||
use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
|
||||
use self::namespace::mangled_name_of_instance;
|
||||
use self::type_names::compute_debuginfo_type_name;
|
||||
use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
|
||||
|
||||
use crate::abi::FnAbi;
|
||||
|
@ -311,10 +310,10 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
|
||||
};
|
||||
|
||||
// Find the enclosing function, in case this is a closure.
|
||||
let def_key = self.tcx().def_key(def_id);
|
||||
let mut name = def_key.disambiguated_data.data.to_string();
|
||||
let mut name = String::new();
|
||||
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
|
||||
|
||||
// Find the enclosing function, in case this is a closure.
|
||||
let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
|
||||
|
||||
// Get_template_parameters() will append a `<...>` clause to the function
|
||||
|
@ -428,24 +427,16 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
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), &[]);
|
||||
}
|
||||
|
||||
name_to_append_suffix_to.push('<');
|
||||
for (i, actual_type) in substs.types().enumerate() {
|
||||
if i != 0 {
|
||||
name_to_append_suffix_to.push(',');
|
||||
}
|
||||
|
||||
let actual_type =
|
||||
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type);
|
||||
// Add actual type name to <...> clause of function name
|
||||
let actual_type_name = compute_debuginfo_type_name(cx.tcx(), actual_type, true);
|
||||
name_to_append_suffix_to.push_str(&actual_type_name[..]);
|
||||
}
|
||||
name_to_append_suffix_to.push('>');
|
||||
|
||||
// Again, only create type information if full debuginfo is enabled
|
||||
let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
|
||||
let names = get_parameter_names(cx, generics);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// Namespace Handling.
|
||||
|
||||
use super::utils::{debug_context, DIB};
|
||||
use rustc_codegen_ssa::debuginfo::type_names;
|
||||
use rustc_middle::ty::{self, Instance};
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::llvm;
|
||||
use crate::llvm::debuginfo::DIScope;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
|
||||
pub fn mangled_name_of_instance<'a, 'tcx>(
|
||||
cx: &CodegenCx<'a, 'tcx>,
|
||||
|
@ -27,25 +27,18 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
|
|||
.parent
|
||||
.map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent }));
|
||||
|
||||
let crate_name_as_str;
|
||||
let name_to_string;
|
||||
let namespace_name = match def_key.disambiguated_data.data {
|
||||
DefPathData::CrateRoot => {
|
||||
crate_name_as_str = cx.tcx.crate_name(def_id.krate).as_str();
|
||||
&*crate_name_as_str
|
||||
}
|
||||
data => {
|
||||
name_to_string = data.to_string();
|
||||
&*name_to_string
|
||||
}
|
||||
let namespace_name_string = {
|
||||
let mut output = String::new();
|
||||
type_names::push_item_name(cx.tcx, def_id, false, &mut output);
|
||||
output
|
||||
};
|
||||
|
||||
let scope = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateNameSpace(
|
||||
DIB(cx),
|
||||
parent_scope,
|
||||
namespace_name.as_ptr().cast(),
|
||||
namespace_name.len(),
|
||||
namespace_name_string.as_ptr().cast(),
|
||||
namespace_name_string.len(),
|
||||
false, // ExportSymbols (only relevant for C++ anonymous namespaces)
|
||||
)
|
||||
};
|
||||
|
|
|
@ -1,9 +1,22 @@
|
|||
// Type Names for Debug Info.
|
||||
|
||||
// Notes on targetting MSVC:
|
||||
// In general, MSVC's debugger attempts to parse all arguments as C++ expressions,
|
||||
// even if the argument is explicitly a symbol name.
|
||||
// As such, there are many things that cause parsing issues:
|
||||
// * `#` is treated as a special character for macros.
|
||||
// * `{` or `<` at the beginning of a name is treated as an operator.
|
||||
// * `>>` is always treated as a right-shift.
|
||||
// * `[` in a name is treated like a regex bracket expression (match any char
|
||||
// within the brackets).
|
||||
// * `"` is treated as the start of a string.
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt};
|
||||
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||
use rustc_target::abi::{TagEncoding, Variants};
|
||||
|
||||
use std::fmt::Write;
|
||||
|
@ -40,7 +53,13 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
ty::Bool => output.push_str("bool"),
|
||||
ty::Char => output.push_str("char"),
|
||||
ty::Str => output.push_str("str"),
|
||||
ty::Never => output.push('!'),
|
||||
ty::Never => {
|
||||
if cpp_like_names {
|
||||
output.push_str("never$");
|
||||
} else {
|
||||
output.push('!');
|
||||
}
|
||||
}
|
||||
ty::Int(int_ty) => output.push_str(int_ty.name_str()),
|
||||
ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()),
|
||||
ty::Float(float_ty) => output.push_str(float_ty.name_str()),
|
||||
|
@ -50,12 +69,12 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
msvc_enum_fallback(tcx, t, def, substs, output, visited);
|
||||
} else {
|
||||
push_item_name(tcx, def.did, qualified, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
push_generic_params_internal(tcx, substs, output, visited);
|
||||
}
|
||||
}
|
||||
ty::Tuple(component_types) => {
|
||||
if cpp_like_names {
|
||||
output.push_str("tuple<");
|
||||
output.push_str("tuple$<");
|
||||
} else {
|
||||
output.push('(');
|
||||
}
|
||||
|
@ -70,54 +89,79 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
}
|
||||
|
||||
if cpp_like_names {
|
||||
output.push('>');
|
||||
push_close_angle_bracket(tcx, output);
|
||||
} else {
|
||||
output.push(')');
|
||||
}
|
||||
}
|
||||
ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
|
||||
if !cpp_like_names {
|
||||
if cpp_like_names {
|
||||
match mutbl {
|
||||
hir::Mutability::Not => output.push_str("ptr_const$<"),
|
||||
hir::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 "),
|
||||
match mutbl {
|
||||
hir::Mutability::Not => output.push_str("const "),
|
||||
hir::Mutability::Mut => output.push_str("mut "),
|
||||
}
|
||||
}
|
||||
|
||||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
|
||||
|
||||
if cpp_like_names {
|
||||
output.push('*');
|
||||
push_close_angle_bracket(tcx, output);
|
||||
}
|
||||
}
|
||||
ty::Ref(_, inner_type, mutbl) => {
|
||||
// Slices and `&str` are treated like C++ pointers when computing debug
|
||||
// info for MSVC debugger. However, wrapping these types' names in a synthetic type
|
||||
// causes the .natvis engine for WinDbg to fail to display their data, so we opt these
|
||||
// types out to aid debugging in MSVC.
|
||||
let is_slice_or_str = match *inner_type.kind() {
|
||||
ty::Slice(_) | ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !cpp_like_names {
|
||||
output.push('&');
|
||||
}
|
||||
output.push_str(mutbl.prefix_str());
|
||||
|
||||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
|
||||
if cpp_like_names {
|
||||
// Slices and `&str` are treated like C++ pointers when computing debug
|
||||
// info for MSVC debugger. However, adding '*' at the end of these types' names
|
||||
// causes the .natvis engine for WinDbg to fail to display their data, so we opt these
|
||||
// types out to aid debugging in MSVC.
|
||||
match *inner_type.kind() {
|
||||
ty::Slice(_) | ty::Str => {}
|
||||
_ => output.push('*'),
|
||||
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$<"),
|
||||
}
|
||||
}
|
||||
|
||||
push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
|
||||
|
||||
if cpp_like_names && !is_slice_or_str {
|
||||
push_close_angle_bracket(tcx, output);
|
||||
}
|
||||
}
|
||||
ty::Array(inner_type, len) => {
|
||||
output.push('[');
|
||||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
output.push_str(&format!("; {}", len.eval_usize(tcx, ty::ParamEnv::reveal_all())));
|
||||
output.push(']');
|
||||
if cpp_like_names {
|
||||
output.push_str("array$<");
|
||||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
match len.val {
|
||||
ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(),
|
||||
_ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
|
||||
.unwrap(),
|
||||
}
|
||||
} else {
|
||||
output.push('[');
|
||||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
match len.val {
|
||||
ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(),
|
||||
_ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Slice(inner_type) => {
|
||||
if cpp_like_names {
|
||||
output.push_str("slice<");
|
||||
output.push_str("slice$<");
|
||||
} else {
|
||||
output.push('[');
|
||||
}
|
||||
|
@ -125,19 +169,69 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
|
||||
if cpp_like_names {
|
||||
output.push('>');
|
||||
push_close_angle_bracket(tcx, output);
|
||||
} else {
|
||||
output.push(']');
|
||||
}
|
||||
}
|
||||
ty::Dynamic(ref trait_data, ..) => {
|
||||
if cpp_like_names {
|
||||
output.push_str("dyn$<");
|
||||
} else {
|
||||
output.push_str("dyn ");
|
||||
}
|
||||
|
||||
if let Some(principal) = trait_data.principal() {
|
||||
let principal =
|
||||
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
|
||||
push_item_name(tcx, principal.def_id, false, output);
|
||||
push_type_params(tcx, principal.substs, output, visited);
|
||||
push_item_name(tcx, principal.def_id, qualified, output);
|
||||
push_generic_params_internal(tcx, principal.substs, output, visited);
|
||||
} else {
|
||||
output.push_str("dyn '_");
|
||||
// The auto traits come ordered by `DefPathHash`, which guarantees stability if the
|
||||
// environment is stable (e.g., incremental builds) but not otherwise (e.g.,
|
||||
// updated compiler version, different target).
|
||||
//
|
||||
// To avoid that causing instabilities in test output, sort the auto-traits
|
||||
// alphabetically.
|
||||
let mut auto_traits: Vec<_> = trait_data
|
||||
.iter()
|
||||
.filter_map(|predicate| {
|
||||
match tcx.normalize_erasing_late_bound_regions(
|
||||
ty::ParamEnv::reveal_all(),
|
||||
predicate,
|
||||
) {
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
let mut name = String::new();
|
||||
push_item_name(tcx, def_id, true, &mut name);
|
||||
Some(name)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
auto_traits.sort();
|
||||
|
||||
for name in auto_traits {
|
||||
output.push_str(&name);
|
||||
|
||||
if cpp_like_names {
|
||||
output.push_str(", ");
|
||||
} else {
|
||||
output.push_str(" + ");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the trailing joining characters. For cpp_like_names
|
||||
// this is `, ` otherwise ` + `.
|
||||
output.pop();
|
||||
output.pop();
|
||||
if !cpp_like_names {
|
||||
output.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if cpp_like_names {
|
||||
push_close_angle_bracket(tcx, output);
|
||||
}
|
||||
}
|
||||
ty::FnDef(..) | ty::FnPtr(_) => {
|
||||
|
@ -155,23 +249,37 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
// use a dummy string that should make it clear
|
||||
// that something unusual is going on
|
||||
if !visited.insert(t) {
|
||||
output.push_str("<recursive_type>");
|
||||
output.push_str(if cpp_like_names {
|
||||
"recursive_type$"
|
||||
} else {
|
||||
"<recursive_type>"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let sig = t.fn_sig(tcx);
|
||||
output.push_str(sig.unsafety().prefix_str());
|
||||
let sig =
|
||||
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx));
|
||||
|
||||
let abi = sig.abi();
|
||||
if abi != rustc_target::spec::abi::Abi::Rust {
|
||||
output.push_str("extern \"");
|
||||
output.push_str(abi.name());
|
||||
output.push_str("\" ");
|
||||
if cpp_like_names {
|
||||
// Format as a C++ function pointer: return_type (*)(params...)
|
||||
if sig.output().is_unit() {
|
||||
output.push_str("void");
|
||||
} else {
|
||||
push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
|
||||
}
|
||||
output.push_str(" (*)(");
|
||||
} else {
|
||||
output.push_str(sig.unsafety.prefix_str());
|
||||
|
||||
if sig.abi != rustc_target::spec::abi::Abi::Rust {
|
||||
output.push_str("extern \"");
|
||||
output.push_str(sig.abi.name());
|
||||
output.push_str("\" ");
|
||||
}
|
||||
|
||||
output.push_str("fn(");
|
||||
}
|
||||
|
||||
output.push_str("fn(");
|
||||
|
||||
let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
|
||||
if !sig.inputs().is_empty() {
|
||||
for ¶meter_type in sig.inputs() {
|
||||
push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
|
||||
|
@ -191,7 +299,7 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
|
||||
output.push(')');
|
||||
|
||||
if !sig.output().is_unit() {
|
||||
if !cpp_like_names && !sig.output().is_unit() {
|
||||
output.push_str(" -> ");
|
||||
push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
|
||||
}
|
||||
|
@ -207,17 +315,14 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
// processing
|
||||
visited.remove(t);
|
||||
}
|
||||
ty::Closure(def_id, ..) => {
|
||||
output.push_str(&format!(
|
||||
"closure-{}",
|
||||
tcx.def_key(def_id).disambiguated_data.disambiguator
|
||||
));
|
||||
}
|
||||
ty::Generator(def_id, ..) => {
|
||||
output.push_str(&format!(
|
||||
"generator-{}",
|
||||
tcx.def_key(def_id).disambiguated_data.disambiguator
|
||||
));
|
||||
ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
|
||||
let key = tcx.def_key(def_id);
|
||||
if qualified {
|
||||
let parent_def_id = DefId { index: 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);
|
||||
}
|
||||
// Type parameters from polymorphized functions.
|
||||
ty::Param(_) => {
|
||||
|
@ -273,7 +378,7 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
|
||||
output.push_str("enum$<");
|
||||
push_item_name(tcx, def.did, true, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
push_generic_params_internal(tcx, substs, output, visited);
|
||||
|
||||
let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
|
||||
|
||||
|
@ -281,47 +386,116 @@ pub fn push_debuginfo_type_name<'tcx>(
|
|||
} else {
|
||||
output.push_str("enum$<");
|
||||
push_item_name(tcx, def.did, true, output);
|
||||
push_type_params(tcx, substs, output, visited);
|
||||
output.push('>');
|
||||
push_generic_params_internal(tcx, substs, output, visited);
|
||||
push_close_angle_bracket(tcx, output);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
|
||||
if qualified {
|
||||
output.push_str(&tcx.crate_name(def_id.krate).as_str());
|
||||
for path_element in tcx.def_path(def_id).data {
|
||||
write!(output, "::{}", path_element.data).unwrap();
|
||||
}
|
||||
} else {
|
||||
output.push_str(&tcx.item_name(def_id).as_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Pushes the type 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_type_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
substs: SubstsRef<'tcx>,
|
||||
output: &mut String,
|
||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
if substs.types().next().is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
output.push('<');
|
||||
|
||||
for type_parameter in substs.types() {
|
||||
push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
|
||||
output.push_str(", ");
|
||||
}
|
||||
|
||||
output.pop();
|
||||
output.pop();
|
||||
|
||||
output.push('>');
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
|
||||
let def_key = tcx.def_key(def_id);
|
||||
if qualified {
|
||||
if let Some(parent) = def_key.parent {
|
||||
push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
|
||||
output.push_str("::");
|
||||
}
|
||||
}
|
||||
|
||||
push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
|
||||
}
|
||||
|
||||
fn push_unqualified_item_name(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
disambiguated_data: DisambiguatedDefPathData,
|
||||
output: &mut String,
|
||||
) {
|
||||
let cpp_like_names = tcx.sess.target.is_like_msvc;
|
||||
|
||||
match disambiguated_data.data {
|
||||
DefPathData::CrateRoot => {
|
||||
output.push_str(&tcx.crate_name(def_id.krate).as_str());
|
||||
}
|
||||
DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
|
||||
// Generators look like closures, but we want to treat them differently
|
||||
// in the debug info.
|
||||
if cpp_like_names {
|
||||
write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
|
||||
} else {
|
||||
write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap();
|
||||
}
|
||||
}
|
||||
_ => match disambiguated_data.data.name() {
|
||||
DefPathDataName::Named(name) => {
|
||||
output.push_str(&name.as_str());
|
||||
}
|
||||
DefPathDataName::Anon { namespace } => {
|
||||
if cpp_like_names {
|
||||
write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap();
|
||||
} else {
|
||||
write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// 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>,
|
||||
output: &mut String,
|
||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
if substs.non_erasable_generics().next().is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs));
|
||||
|
||||
output.push('<');
|
||||
|
||||
for type_parameter in substs.non_erasable_generics() {
|
||||
match type_parameter {
|
||||
GenericArgKind::Type(type_parameter) => {
|
||||
push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
|
||||
output.push_str(", ");
|
||||
}
|
||||
GenericArgKind::Const(const_parameter) => match const_parameter.val {
|
||||
ty::ConstKind::Param(param) => write!(output, "{}, ", param.name).unwrap(),
|
||||
_ => write!(
|
||||
output,
|
||||
"0x{:x}, ",
|
||||
const_parameter.eval_bits(tcx, ty::ParamEnv::reveal_all(), const_parameter.ty)
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
other => bug!("Unexpected non-erasable generic: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
output.pop();
|
||||
output.pop();
|
||||
|
||||
push_close_angle_bracket(tcx, output);
|
||||
}
|
||||
|
||||
pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, output: &mut String) {
|
||||
let mut visited = FxHashSet::default();
|
||||
push_generic_params_internal(tcx, substs, output, &mut visited);
|
||||
}
|
||||
|
||||
fn push_close_angle_bracket<'tcx>(tcx: TyCtxt<'tcx>, output: &mut String) {
|
||||
// MSVC debugger always treats `>>` as a shift, even when parsing templates,
|
||||
// so add a space to avoid confusion.
|
||||
if tcx.sess.target.is_like_msvc && output.ends_with('>') {
|
||||
output.push(' ')
|
||||
};
|
||||
|
||||
output.push('>');
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="slice<*>">
|
||||
<Type Name="slice$<*>">
|
||||
<DisplayString>{{ len={length} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[len]" ExcludeView="simple">length</Item>
|
||||
|
@ -25,23 +25,23 @@
|
|||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<>">
|
||||
<Type Name="tuple$<>">
|
||||
<DisplayString>()</DisplayString>
|
||||
</Type>
|
||||
<Type Name="tuple<*>">
|
||||
<Type Name="tuple$<*>">
|
||||
<DisplayString>({__0})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*>">
|
||||
<Type Name="tuple$<*,*>">
|
||||
<DisplayString>({__0}, {__1})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
<Item Name="[1]">__1</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*>">
|
||||
<Type Name="tuple$<*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -49,7 +49,7 @@
|
|||
<Item Name="[2]">__2</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -58,7 +58,7 @@
|
|||
<Item Name="[3]">__3</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3}, {__4})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -68,7 +68,7 @@
|
|||
<Item Name="[4]">__4</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3}, {__4}, {__5})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -79,7 +79,7 @@
|
|||
<Item Name="[5]">__5</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -91,7 +91,7 @@
|
|||
<Item Name="[6]">__6</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*,*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*,*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -104,7 +104,7 @@
|
|||
<Item Name="[7]">__7</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*,*,*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*,*,*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}, {__8})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -118,7 +118,7 @@
|
|||
<Item Name="[8]">__8</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*,*,*,*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*,*,*,*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}, {__8}, {__9})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
@ -133,7 +133,7 @@
|
|||
<Item Name="[9]">__9</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="tuple<*,*,*,*,*,*,*,*,*,*,*>">
|
||||
<Type Name="tuple$<*,*,*,*,*,*,*,*,*,*,*>">
|
||||
<DisplayString>({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}, {__8}, {__9}, ...)</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[0]">__0</Item>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<If Condition="(base.table.table.ctrl.pointer[i] & 0x80) == 0">
|
||||
<!-- Bucket is populated -->
|
||||
<Exec>n--</Exec>
|
||||
<Item Name="{((tuple<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
|
||||
<Item Name="{((tuple$<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple$<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
|
||||
</If>
|
||||
<Exec>i++</Exec>
|
||||
</Loop>
|
||||
|
|
|
@ -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: "generator-0"
|
||||
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator$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,
|
||||
|
|
|
@ -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: "generator-0", scope: [[ASYNC_FN]]
|
||||
// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator#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]*]]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// compile-flags: -g
|
||||
//
|
||||
// CHECK-LABEL: @main
|
||||
// CHECK: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> <recursive_type>",{{.*}}
|
||||
// MSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "recursive_type$ (*)()",{{.*}}
|
||||
// NONMSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> <recursive_type>",{{.*}}
|
||||
//
|
||||
// CHECK: {{.*}}DISubroutineType{{.*}}
|
||||
// CHECK: {{.*}}DIBasicType(name: "<recur_type>", encoding: DW_ATE_unsigned)
|
||||
|
|
|
@ -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$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,
|
||||
|
|
|
@ -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#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]*]]
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
|
||||
// min-lldb-version: 310
|
||||
|
||||
// This fails on lldb 6.0.1 on x86-64 Fedora 28; so mark it macOS-only
|
||||
// for now.
|
||||
// only-macos
|
||||
// This fails on lldb 6.0.1 on x86-64 Fedora 28; so ignore Linux for now.
|
||||
// ignore-linux
|
||||
|
||||
// compile-flags:-g
|
||||
|
||||
|
@ -44,6 +43,9 @@
|
|||
// gdb-check:$13 = 2.5
|
||||
// gdb-command:print f64
|
||||
// gdb-check:$14 = 3.5
|
||||
// gdb-command:print s
|
||||
// gdbg-check:$15 = {data_ptr = [...] "Hello, World!", length = 13}
|
||||
// gdbr-check:$15 = "Hello, World!"
|
||||
|
||||
|
||||
// === LLDB TESTS ==================================================================================
|
||||
|
@ -94,6 +96,41 @@
|
|||
// lldbg-check:[...]$12 = 3.5
|
||||
// lldbr-check:(f64) f64 = 3.5
|
||||
|
||||
|
||||
// === CDB TESTS ===================================================================================
|
||||
|
||||
// cdb-command:g
|
||||
// cdb-command:dx b
|
||||
// cdb-check:b : false [Type: bool]
|
||||
// cdb-command:dx i
|
||||
// cdb-check:i : -1 [Type: __int64]
|
||||
// The variable 'c' doesn't appear for some reason...
|
||||
// cdb-command:dx i8
|
||||
// cdb-check:i8 : 68 [Type: char]
|
||||
// cdb-command:dx i16
|
||||
// cdb-check:i16 : -16 [Type: short]
|
||||
// cdb-command:dx i32
|
||||
// cdb-check:i32 : -32 [Type: int]
|
||||
// cdb-command:dx i64
|
||||
// cdb-check:i64 : -64 [Type: __int64]
|
||||
// cdb-command:dx u
|
||||
// cdb-check:u : 0x1 [Type: [...]]
|
||||
// cdb-command:dx u8
|
||||
// cdb-check:u8 : 0x64 [Type: unsigned char]
|
||||
// cdb-command:dx u16
|
||||
// cdb-check:u16 : 0x10 [Type: unsigned short]
|
||||
// cdb-command:dx u32
|
||||
// cdb-check:u32 : 0x20 [Type: unsigned int]
|
||||
// cdb-command:dx u64
|
||||
// cdb-check:u64 : 0x40 [Type: unsigned __int64]
|
||||
// cdb-command:dx f32
|
||||
// cdb-check:f32 : 2.500000 [Type: float]
|
||||
// cdb-command:dx f64
|
||||
// cdb-check:f64 : 3.500000 [Type: double]
|
||||
// cdb-command:.enable_unicode 1
|
||||
// cdb-command:dx s
|
||||
// cdb-check:s : 72 [Type: str]
|
||||
|
||||
#![allow(unused_variables)]
|
||||
#![feature(omit_gdb_pretty_printer_section)]
|
||||
#![omit_gdb_pretty_printer_section]
|
||||
|
@ -113,6 +150,7 @@ fn main() {
|
|||
let u64: u64 = 64;
|
||||
let f32: f32 = 2.5;
|
||||
let f64: f64 = 3.5;
|
||||
let s: &str = "Hello, World!";
|
||||
_zzz(); // #break
|
||||
}
|
||||
|
||||
|
|
175
src/test/debuginfo/function-names.rs
Normal file
175
src/test/debuginfo/function-names.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
// Function names are formatted differently in old versions of GDB
|
||||
// min-gdb-version: 9.2
|
||||
|
||||
// compile-flags:-g
|
||||
|
||||
// === GDB TESTS ===================================================================================
|
||||
|
||||
// Top-level function
|
||||
// gdb-command:info functions -q function_names::main
|
||||
// gdb-check:[...]static fn function_names::main();
|
||||
// gdb-command:info functions -q function_names::generic_func<*
|
||||
// gdb-check:[...]static fn function_names::generic_func(i32) -> i32;
|
||||
|
||||
// Implementations
|
||||
// gdb-command:info functions -q function_names::.*::impl_function.*
|
||||
// gdb-check:[...]static fn function_names::GenericStruct<T1,T2>::impl_function();
|
||||
// gdb-check:[...]static fn function_names::Mod1::TestStruct2::impl_function();
|
||||
// gdb-check:[...]static fn function_names::TestStruct1::impl_function();
|
||||
|
||||
// Trait implementations
|
||||
// gdb-command:info functions -q function_names::.*::trait_function.*
|
||||
// gdb-check:[...]static fn <function_names::GenericStruct<T,i32> as function_names::TestTrait1>::trait_function();
|
||||
// gdb-check:[...]static fn <function_names::GenericStruct<[T; N],f32> as function_names::TestTrait1>::trait_function();
|
||||
// gdb-check:[...]static fn <function_names::Mod1::TestStruct2 as function_names::Mod1::TestTrait2>::trait_function();
|
||||
// gdb-check:[...]static fn <function_names::TestStruct1 as function_names::TestTrait1>::trait_function();
|
||||
|
||||
// Closure
|
||||
// gdb-command:info functions -q function_names::.*::{{closure.*
|
||||
// gdb-check:[...]static fn function_names::GenericStruct<T1,T2>::impl_function::{{closure}}(*mut function_names::{impl#2}::impl_function::{closure#0});
|
||||
// gdb-check:[...]static fn function_names::generic_func::{{closure}}(*mut function_names::generic_func::{closure#0});
|
||||
// gdb-check:[...]static fn function_names::main::{{closure}}(*mut function_names::main::{closure#0});
|
||||
|
||||
// Generator
|
||||
// Generators don't seem to appear in GDB's symbol table.
|
||||
|
||||
// === CDB TESTS ===================================================================================
|
||||
|
||||
// Top-level function
|
||||
// cdb-command:x a!function_names::main
|
||||
// cdb-check:[...] a!function_names::main (void)
|
||||
// cdb-command:x a!function_names::generic_func<*
|
||||
// cdb-check:[...] a!function_names::generic_func<i32> (int)
|
||||
|
||||
// Implementations
|
||||
// cdb-command:x a!function_names::*::impl_function*
|
||||
// cdb-check:[...] a!function_names::Mod1::TestStruct2::impl_function (void)
|
||||
// cdb-check:[...] a!function_names::TestStruct1::impl_function (void)
|
||||
// cdb-check:[...] a!function_names::GenericStruct<i32, i32>::impl_function<i32, i32> (void)
|
||||
|
||||
// Trait implementations
|
||||
// cdb-command:x a!function_names::*::trait_function*
|
||||
// cdb-check:[...] a!function_names::impl$6::trait_function<i32, 0x1> (void)
|
||||
// cdb-check:[...] a!function_names::impl$3::trait_function<i32> (void)
|
||||
// cdb-check:[...] a!function_names::impl$1::trait_function (void)
|
||||
// cdb-check:[...] a!function_names::impl$5::trait_function3<function_names::TestStruct1> (void)
|
||||
// cdb-check:[...] a!function_names::Mod1::impl$1::trait_function (void)
|
||||
|
||||
// Closure
|
||||
// cdb-command:x a!function_names::*::closure*
|
||||
// cdb-check:[...] a!function_names::main::closure$0 (void)
|
||||
// cdb-check:[...] a!function_names::generic_func::closure$0<i32> (void)
|
||||
// cdb-check:[...] a!function_names::impl$2::impl_function::closure$0<i32, i32> (void)
|
||||
|
||||
// Generator
|
||||
// cdb-command:x a!function_names::*::generator*
|
||||
// cdb-check:[...] a!function_names::main::generator$1 (void)
|
||||
|
||||
#![allow(unused_variables)]
|
||||
#![feature(omit_gdb_pretty_printer_section)]
|
||||
#![omit_gdb_pretty_printer_section]
|
||||
#![feature(generators, generator_trait)]
|
||||
|
||||
use Mod1::TestTrait2;
|
||||
use std::ops::Generator;
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
// Implementations
|
||||
TestStruct1::impl_function();
|
||||
Mod1::TestStruct2::impl_function();
|
||||
GenericStruct::<i32, i32>::impl_function();
|
||||
|
||||
// Trait implementations
|
||||
TestStruct1::trait_function();
|
||||
Mod1::TestStruct2::trait_function();
|
||||
GenericStruct::<i32, i32>::trait_function();
|
||||
GenericStruct::<[i32; 1], f32>::trait_function();
|
||||
GenericStruct::<TestStruct1, usize>::trait_function3();
|
||||
|
||||
// Generic function
|
||||
let _ = generic_func(42);
|
||||
|
||||
// Closure
|
||||
let closure = || { TestStruct1 };
|
||||
closure();
|
||||
|
||||
// Generator
|
||||
let mut generator = || { yield; return; };
|
||||
Pin::new(&mut generator).resume(());
|
||||
}
|
||||
|
||||
struct TestStruct1;
|
||||
trait TestTrait1 {
|
||||
fn trait_function();
|
||||
}
|
||||
|
||||
// Implementation
|
||||
impl TestStruct1 {
|
||||
pub fn impl_function() {}
|
||||
}
|
||||
|
||||
// Implementation for a trait
|
||||
impl TestTrait1 for TestStruct1 {
|
||||
fn trait_function() {}
|
||||
}
|
||||
|
||||
// Implementation and implementation within a mod
|
||||
mod Mod1 {
|
||||
pub struct TestStruct2;
|
||||
pub trait TestTrait2 {
|
||||
fn trait_function();
|
||||
}
|
||||
|
||||
impl TestStruct2 {
|
||||
pub fn impl_function() {}
|
||||
}
|
||||
|
||||
impl TestTrait2 for TestStruct2 {
|
||||
fn trait_function() {}
|
||||
}
|
||||
}
|
||||
|
||||
struct GenericStruct<T1, T2>(std::marker::PhantomData<(T1, T2)>);
|
||||
|
||||
// Generic implementation
|
||||
impl<T1, T2> GenericStruct<T1, T2> {
|
||||
pub fn impl_function() {
|
||||
// Closure in a generic implementation
|
||||
let closure = || { TestStruct1 };
|
||||
closure();
|
||||
}
|
||||
}
|
||||
|
||||
// Generic trait implementation
|
||||
impl<T> TestTrait1 for GenericStruct<T, i32> {
|
||||
fn trait_function() {}
|
||||
}
|
||||
|
||||
// Implementation based on associated type
|
||||
trait TestTrait3 {
|
||||
type AssocType;
|
||||
fn trait_function3();
|
||||
}
|
||||
impl TestTrait3 for TestStruct1 {
|
||||
type AssocType = usize;
|
||||
fn trait_function3() {}
|
||||
}
|
||||
impl<T: TestTrait3> TestTrait3 for GenericStruct<T, T::AssocType> {
|
||||
type AssocType = T::AssocType;
|
||||
fn trait_function3() {}
|
||||
}
|
||||
|
||||
// Generic trait implementation with const generics
|
||||
impl<T, const N: usize> TestTrait1 for GenericStruct<[T; N], f32> {
|
||||
fn trait_function() {}
|
||||
}
|
||||
|
||||
// Generic function
|
||||
fn generic_func<T>(value: T) -> T {
|
||||
// Closure in a generic function
|
||||
let closure = || { TestStruct1 };
|
||||
closure();
|
||||
|
||||
value
|
||||
}
|
|
@ -11,31 +11,31 @@
|
|||
|
||||
// gdb-command:run
|
||||
// gdb-command:print b
|
||||
// gdb-check:$1 = generator_objects::main::generator-0::Unresumed(0x[...])
|
||||
// gdb-check:$1 = generator_objects::main::{generator#0}::Unresumed(0x[...])
|
||||
// gdb-command:continue
|
||||
// gdb-command:print b
|
||||
// gdb-check:$2 = generator_objects::main::generator-0::Suspend0{c: 6, d: 7, __0: 0x[...]}
|
||||
// gdb-check:$2 = generator_objects::main::{generator#0}::Suspend0{c: 6, d: 7, __0: 0x[...]}
|
||||
// gdb-command:continue
|
||||
// gdb-command:print b
|
||||
// gdb-check:$3 = generator_objects::main::generator-0::Suspend1{c: 7, d: 8, __0: 0x[...]}
|
||||
// gdb-check:$3 = generator_objects::main::{generator#0}::Suspend1{c: 7, d: 8, __0: 0x[...]}
|
||||
// gdb-command:continue
|
||||
// gdb-command:print b
|
||||
// gdb-check:$4 = generator_objects::main::generator-0::Returned(0x[...])
|
||||
// gdb-check:$4 = generator_objects::main::{generator#0}::Returned(0x[...])
|
||||
|
||||
// === LLDB TESTS ==================================================================================
|
||||
|
||||
// lldb-command:run
|
||||
// lldb-command:print b
|
||||
// lldbg-check:(generator_objects::main::generator-0) $0 =
|
||||
// lldbg-check:(generator_objects::main::{generator#0}) $0 =
|
||||
// lldb-command:continue
|
||||
// lldb-command:print b
|
||||
// lldbg-check:(generator_objects::main::generator-0) $1 =
|
||||
// lldbg-check:(generator_objects::main::{generator#0}) $1 =
|
||||
// lldb-command:continue
|
||||
// lldb-command:print b
|
||||
// lldbg-check:(generator_objects::main::generator-0) $2 =
|
||||
// lldbg-check:(generator_objects::main::{generator#0}) $2 =
|
||||
// lldb-command:continue
|
||||
// lldb-command:print b
|
||||
// lldbg-check:(generator_objects::main::generator-0) $3 =
|
||||
// lldbg-check:(generator_objects::main::{generator#0}) $3 =
|
||||
|
||||
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
|
||||
#![omit_gdb_pretty_printer_section]
|
||||
|
|
|
@ -39,6 +39,27 @@
|
|||
// lldbg-check:[...]$3 = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
|
||||
// lldbr-check:(generic_struct::AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>>) float_int_float = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
|
||||
|
||||
// === CDB TESTS ===================================================================================
|
||||
|
||||
// cdb-command:g
|
||||
|
||||
// cdb-command:dx int_int
|
||||
// cdb-check:int_int [Type: generic_struct::AGenericStruct<i32, i32>]
|
||||
// cdb-check:[...]key : 0 [Type: int]
|
||||
// cdb-check:[...]value : 1 [Type: int]
|
||||
// cdb-command:dx int_float
|
||||
// cdb-check:int_float [Type: generic_struct::AGenericStruct<i32, f64>]
|
||||
// cdb-check:[...]key : 2 [Type: int]
|
||||
// cdb-check:[...]value : 3.500000 [Type: double]
|
||||
// cdb-command:dx float_int
|
||||
// cdb-check:float_int [Type: generic_struct::AGenericStruct<f64, i32>]
|
||||
// cdb-check:[...]key : 4.500000 [Type: double]
|
||||
// cdb-check:[...]value : 5 [Type: int]
|
||||
// cdb-command:dx float_int_float
|
||||
// cdb-check:float_int_float [Type: generic_struct::AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64> >]
|
||||
// cdb-check:[...]key : 6.500000 [Type: double]
|
||||
// cdb-check:[...]value [Type: generic_struct::AGenericStruct<i32, f64>]
|
||||
|
||||
|
||||
#![feature(omit_gdb_pretty_printer_section)]
|
||||
#![omit_gdb_pretty_printer_section]
|
||||
|
|
|
@ -11,20 +11,20 @@
|
|||
// gdb-command:run
|
||||
|
||||
// gdb-command:print g
|
||||
// gdb-check:$1 = issue_57822::main::closure-1 (issue_57822::main::closure-0 (1))
|
||||
// gdb-check:$1 = issue_57822::main::{closure#1} (issue_57822::main::{closure#0} (1))
|
||||
|
||||
// gdb-command:print b
|
||||
// gdb-check:$2 = issue_57822::main::generator-3::Unresumed(issue_57822::main::generator-2::Unresumed(2))
|
||||
// gdb-check:$2 = issue_57822::main::{generator#3}::Unresumed(issue_57822::main::{generator#2}::Unresumed(2))
|
||||
|
||||
// === LLDB TESTS ==================================================================================
|
||||
|
||||
// lldb-command:run
|
||||
|
||||
// lldb-command:print g
|
||||
// lldbg-check:(issue_57822::main::closure-1) $0 = { 0 = { 0 = 1 } }
|
||||
// lldbg-check:(issue_57822::main::{closure#1}) $0 = { 0 = { 0 = 1 } }
|
||||
|
||||
// lldb-command:print b
|
||||
// lldbg-check:(issue_57822::main::generator-3) $1 =
|
||||
// lldbg-check:(issue_57822::main::{generator#3}) $1 =
|
||||
|
||||
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
|
||||
#![omit_gdb_pretty_printer_section]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// only-cdb
|
||||
// ignore-tidy-linelength
|
||||
// compile-flags:-g
|
||||
|
||||
// cdb-command: g
|
||||
|
@ -8,61 +7,61 @@
|
|||
// so the best we can do is to make sure we are generating the right debuginfo
|
||||
|
||||
// cdb-command: dx -r2 a,!
|
||||
// cdb-check:a,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
|
||||
// cdb-check:a,! : Some({...}) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Some]
|
||||
// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
|
||||
// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
|
||||
// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Discriminant$]
|
||||
|
||||
// cdb-command: dx -r2 b,!
|
||||
// cdb-check:b,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
|
||||
// cdb-check:b,! : None [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Some]
|
||||
// cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
|
||||
// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
|
||||
// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum> >, 2, 16, Some>::Discriminant$]
|
||||
|
||||
// cdb-command: dx -r2 c,!
|
||||
// cdb-check:c,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
|
||||
// cdb-check:c,! : Tag1 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
|
||||
// cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
|
||||
// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
|
||||
|
||||
// cdb-command: dx -r2 d,!
|
||||
// cdb-check:d,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
|
||||
// cdb-check:d,! : Data({...}) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
|
||||
// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
|
||||
// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
|
||||
|
||||
// cdb-command: dx -r2 e,!
|
||||
// cdb-check:e,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
|
||||
// cdb-check:e,! : Tag2 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
|
||||
// cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum]
|
||||
// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
|
||||
|
||||
// cdb-command: dx -r2 f,!
|
||||
// cdb-check:f,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
|
||||
// cdb-check:f,! : Some({...}) [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Some]
|
||||
// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *]
|
||||
// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
|
||||
// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Discriminant$]
|
||||
|
||||
// cdb-command: dx -r2 g,!
|
||||
// cdb-check:g,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
|
||||
// cdb-check:g,! : None [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Some]
|
||||
// cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *]
|
||||
// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
|
||||
// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>::Discriminant$]
|
||||
|
||||
// cdb-command: dx h
|
||||
// cdb-check:h : Some [Type: enum$<core::option::Option<u32>>]
|
||||
// cdb-check:h : Some [Type: enum$<core::option::Option<u32> >]
|
||||
// cdb-check: [+0x000] variant$ : Some (0x1) [Type: core::option::Option]
|
||||
// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int]
|
||||
|
||||
// cdb-command: dx i
|
||||
// cdb-check:i : None [Type: enum$<core::option::Option<u32>>]
|
||||
// cdb-check:i : None [Type: enum$<core::option::Option<u32> >]
|
||||
// cdb-check: [+0x000] variant$ : None (0x0) [Type: core::option::Option]
|
||||
|
||||
// cdb-command: dx j
|
||||
// cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
|
||||
|
||||
// cdb-command: dx -r2 k,!
|
||||
// cdb-check:k,! [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
|
||||
// cdb-check:k,! : Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
|
||||
// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Some]
|
||||
// cdb-check: [+0x000] __0 [Type: alloc::string::String]
|
||||
// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$]
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// cdb-only
|
||||
// min-cdb-version: 10.0.21287.1005
|
||||
// compile-flags:-g
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// === CDB TESTS ==================================================================================
|
||||
//
|
||||
|
@ -22,7 +21,7 @@
|
|||
|
||||
//
|
||||
// cdb-command:dx lock,d
|
||||
// cdb-check:lock,d : Ok [Type: enum$<core::result::Result<std::sync::mutex::MutexGuard<i32>, enum$<std::sync::poison::TryLockError<std::sync::mutex::MutexGuard<i32>>, 0, 1, Poisoned>>>]
|
||||
// cdb-check:lock,d : Ok [Type: enum$<core::result::Result<std::sync::mutex::MutexGuard<i32>, enum$<std::sync::poison::TryLockError<std::sync::mutex::MutexGuard<i32> >, 0, 1, Poisoned> > >]
|
||||
// cdb-check: [...] variant$ : Ok (0) [Type: core::result::Result]
|
||||
// cdb-check: [...] __0 [Type: std::sync::mutex::MutexGuard<i32>]
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// ignore-freebsd: gdb package too new
|
||||
// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
|
||||
// ignore-android: FIXME(#10381)
|
||||
// ignore-tidy-linelength
|
||||
// compile-flags:-g
|
||||
// min-gdb-version: 7.7
|
||||
// min-lldb-version: 310
|
||||
|
@ -72,7 +71,7 @@
|
|||
// cdb-command: g
|
||||
|
||||
// cdb-command: dx slice,d
|
||||
// cdb-check:slice,d : { len=4 } [Type: slice<i32>]
|
||||
// cdb-check:slice,d : { len=4 } [Type: slice$<i32>]
|
||||
// cdb-check: [len] : 4 [Type: [...]]
|
||||
// cdb-check: [0] : 0 [Type: int]
|
||||
// cdb-check: [1] : 1 [Type: int]
|
||||
|
@ -116,17 +115,18 @@
|
|||
// NOTE: OsString doesn't have a .natvis entry yet.
|
||||
|
||||
// cdb-command: dx some
|
||||
// cdb-check:some : Some [Type: enum$<core::option::Option<i16>>]
|
||||
// cdb-check:some : Some [Type: enum$<core::option::Option<i16> >]
|
||||
// cdb-check: [...] variant$ : Some (0x1) [Type: core::option::Option]
|
||||
// cdb-check: [...] __0 : 8 [Type: short]
|
||||
|
||||
// cdb-command: dx none
|
||||
// cdb-check:none : None [Type: enum$<core::option::Option<i64>>]
|
||||
// cdb-check:none : None [Type: enum$<core::option::Option<i64> >]
|
||||
// cdb-check: [...] variant$ : None (0x0) [Type: core::option::Option]
|
||||
|
||||
// cdb-command: dx some_string
|
||||
// NOTE: cdb fails to interpret debug info of Option enums on i686.
|
||||
// cdb-check:some_string [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
|
||||
// cdb-check:some_string : Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
|
||||
// cdb-check: [...] __0 : "IAMA optional string!" [Type: alloc::string::String]
|
||||
|
||||
#![allow(unused_variables)]
|
||||
use std::ffi::OsString;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// pretty-printers are not loaded
|
||||
// compile-flags:-g
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// min-gdb-version: 8.1
|
||||
// min-cdb-version: 10.0.18317.1001
|
||||
|
@ -36,7 +35,7 @@
|
|||
|
||||
// cdb-command:dx w1,d
|
||||
// cdb-check:w1,d [Type: alloc::rc::Weak<i32>]
|
||||
// cdb-check: [...] ptr : [...] [Type: core::ptr::non_null::NonNull<alloc::rc::RcBox<i32>>]
|
||||
// cdb-check: [...] ptr : [...] [Type: core::ptr::non_null::NonNull<alloc::rc::RcBox<i32> >]
|
||||
|
||||
// cdb-command:dx a,d
|
||||
// cdb-check:a,d : 42 [Type: alloc::sync::Arc<i32>]
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
// cdb-command: g
|
||||
|
||||
// cdb-command: dx x,d
|
||||
// cdb-check:x,d : Ok [Type: enum$<core::result::Result<i32, str>>]
|
||||
// cdb-check:x,d : Ok [Type: enum$<core::result::Result<i32, str> >]
|
||||
// cdb-check: [...] __0 : -3 [Type: int]
|
||||
|
||||
// cdb-command: dx y
|
||||
// cdb-check:y : Err [Type: enum$<core::result::Result<i32, str>>]
|
||||
// cdb-check:y : Err [Type: enum$<core::result::Result<i32, str> >]
|
||||
// cdb-check: [...] __0 : "Some error message" [Type: str]
|
||||
|
||||
fn main()
|
||||
|
|
|
@ -129,38 +129,38 @@
|
|||
// cdb-command: g
|
||||
|
||||
// cdb-command:dx noPadding8,d
|
||||
// cdb-check:noPadding8,d [...]: (-100, 100) [Type: tuple<i8, u8>]
|
||||
// cdb-check:noPadding8,d [...]: (-100, 100) [Type: tuple$<i8, u8>]
|
||||
// cdb-check:[...][0] : -100 [Type: [...]]
|
||||
// cdb-check:[...][1] : 100 [Type: [...]]
|
||||
// cdb-command:dx noPadding16,d
|
||||
// cdb-check:noPadding16,d [...]: (0, 1, 2) [Type: tuple<i16, i16, u16>]
|
||||
// cdb-check:noPadding16,d [...]: (0, 1, 2) [Type: tuple$<i16, i16, u16>]
|
||||
// cdb-check:[...][0] : 0 [Type: [...]]
|
||||
// cdb-check:[...][1] : 1 [Type: [...]]
|
||||
// cdb-check:[...][2] : 2 [Type: [...]]
|
||||
// cdb-command:dx noPadding32,d
|
||||
// cdb-check:noPadding32,d [...]: (3, 4.5[...], 5) [Type: tuple<i32, f32, u32>]
|
||||
// cdb-check:noPadding32,d [...]: (3, 4.5[...], 5) [Type: tuple$<i32, f32, u32>]
|
||||
// cdb-check:[...][0] : 3 [Type: [...]]
|
||||
// cdb-check:[...][1] : 4.5[...] [Type: [...]]
|
||||
// cdb-check:[...][2] : 5 [Type: [...]]
|
||||
// cdb-command:dx noPadding64,d
|
||||
// cdb-check:noPadding64,d [...]: (6, 7.5[...], 8) [Type: tuple<i64, f64, u64>]
|
||||
// cdb-check:noPadding64,d [...]: (6, 7.5[...], 8) [Type: tuple$<i64, f64, u64>]
|
||||
// cdb-check:[...][0] : 6 [Type: [...]]
|
||||
// cdb-check:[...][1] : 7.500000 [Type: [...]]
|
||||
// cdb-check:[...][2] : 8 [Type: [...]]
|
||||
|
||||
// cdb-command:dx internalPadding1,d
|
||||
// cdb-check:internalPadding1,d [...]: (9, 10) [Type: tuple<i16, i32>]
|
||||
// cdb-check:internalPadding1,d [...]: (9, 10) [Type: tuple$<i16, i32>]
|
||||
// cdb-check:[...][0] : 9 [Type: short]
|
||||
// cdb-check:[...][1] : 10 [Type: int]
|
||||
// cdb-command:dx internalPadding2,d
|
||||
// cdb-check:internalPadding2,d [...]: (11, 12, 13, 14) [Type: tuple<i16, i32, u32, u64>]
|
||||
// cdb-check:internalPadding2,d [...]: (11, 12, 13, 14) [Type: tuple$<i16, i32, u32, u64>]
|
||||
// cdb-check:[...][0] : 11 [Type: [...]]
|
||||
// cdb-check:[...][1] : 12 [Type: [...]]
|
||||
// cdb-check:[...][2] : 13 [Type: [...]]
|
||||
// cdb-check:[...][3] : 14 [Type: [...]]
|
||||
|
||||
// cdb-command:dx paddingAtEnd,d
|
||||
// cdb-check:paddingAtEnd,d [...]: (15, 16) [Type: tuple<i32, i16>]
|
||||
// cdb-check:paddingAtEnd,d [...]: (15, 16) [Type: tuple$<i32, i16>]
|
||||
// cdb-check:[...][0] : 15 [Type: [...]]
|
||||
// cdb-check:[...][1] : 16 [Type: [...]]
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
// cdb-command:g
|
||||
//
|
||||
// cdb-command:dx join_handle,d
|
||||
// cdb-check:join_handle,d [Type: std::thread::JoinHandle<tuple<>>]
|
||||
// cdb-check: [...] __0 [Type: std::thread::JoinInner<tuple<>>]
|
||||
// cdb-check:join_handle,d [Type: std::thread::JoinHandle<tuple$<> >]
|
||||
// cdb-check: [...] __0 [Type: std::thread::JoinInner<tuple$<> >]
|
||||
//
|
||||
// cdb-command:dx t,d
|
||||
// cdb-check:t,d : [...] [Type: std::thread::Thread *]
|
||||
|
|
|
@ -65,64 +65,64 @@
|
|||
// cdb-command: g
|
||||
|
||||
// cdb-command:dx no_padding1,d
|
||||
// cdb-check:no_padding1,d [...]: ((0, 1), 2, 3) [Type: tuple<tuple<u32, u32>, u32, u32>]
|
||||
// cdb-check:[...][0] : (0, 1) [Type: tuple<u32, u32>]
|
||||
// cdb-check:no_padding1,d [...]: ((0, 1), 2, 3) [Type: tuple$<tuple$<u32, u32>, u32, u32>]
|
||||
// cdb-check:[...][0] : (0, 1) [Type: tuple$<u32, u32>]
|
||||
// cdb-check:[...][1] : 2 [Type: [...]]
|
||||
// cdb-check:[...][2] : 3 [Type: [...]]
|
||||
// cdb-command:dx no_padding1.__0,d
|
||||
// cdb-check:no_padding1.__0,d [...]: (0, 1) [Type: tuple<u32, u32>]
|
||||
// cdb-check:no_padding1.__0,d [...]: (0, 1) [Type: tuple$<u32, u32>]
|
||||
// cdb-check:[...][0] : 0 [Type: [...]]
|
||||
// cdb-check:[...][1] : 1 [Type: [...]]
|
||||
// cdb-command:dx no_padding2,d
|
||||
// cdb-check:no_padding2,d [...]: (4, (5, 6), 7) [Type: tuple<u32, tuple<u32, u32>, u32>]
|
||||
// cdb-check:no_padding2,d [...]: (4, (5, 6), 7) [Type: tuple$<u32, tuple$<u32, u32>, u32>]
|
||||
// cdb-check:[...][0] : 4 [Type: [...]]
|
||||
// cdb-check:[...][1] : (5, 6) [Type: tuple<u32, u32>]
|
||||
// cdb-check:[...][1] : (5, 6) [Type: tuple$<u32, u32>]
|
||||
// cdb-check:[...][2] : 7 [Type: [...]]
|
||||
// cdb-command:dx no_padding2.__1,d
|
||||
// cdb-check:no_padding2.__1,d [...]: (5, 6) [Type: tuple<u32, u32>]
|
||||
// cdb-check:no_padding2.__1,d [...]: (5, 6) [Type: tuple$<u32, u32>]
|
||||
// cdb-check:[...][0] : 5 [Type: [...]]
|
||||
// cdb-check:[...][1] : 6 [Type: [...]]
|
||||
// cdb-command:dx no_padding3,d
|
||||
// cdb-check:no_padding3,d [...]: (8, 9, (10, 11)) [Type: tuple<u32, u32, tuple<u32, u32>>]
|
||||
// cdb-check:no_padding3,d [...]: (8, 9, (10, 11)) [Type: tuple$<u32, u32, tuple$<u32, u32> >]
|
||||
// cdb-check:[...][0] : 8 [Type: [...]]
|
||||
// cdb-check:[...][1] : 9 [Type: [...]]
|
||||
// cdb-check:[...][2] : (10, 11) [Type: tuple<u32, u32>]
|
||||
// cdb-check:[...][2] : (10, 11) [Type: tuple$<u32, u32>]
|
||||
// cdb-command:dx no_padding3.__2,d
|
||||
// cdb-check:no_padding3.__2,d [...]: (10, 11) [Type: tuple<u32, u32>]
|
||||
// cdb-check:no_padding3.__2,d [...]: (10, 11) [Type: tuple$<u32, u32>]
|
||||
// cdb-check:[...][0] : 10 [Type: [...]]
|
||||
// cdb-check:[...][1] : 11 [Type: [...]]
|
||||
|
||||
// cdb-command:dx internal_padding1,d
|
||||
// cdb-check:internal_padding1,d [...]: (12, (13, 14)) [Type: tuple<i16, tuple<i32, i32>>]
|
||||
// cdb-check:internal_padding1,d [...]: (12, (13, 14)) [Type: tuple$<i16, tuple$<i32, i32> >]
|
||||
// cdb-check:[...][0] : 12 [Type: [...]]
|
||||
// cdb-check:[...][1] : (13, 14) [Type: tuple<i32, i32>]
|
||||
// cdb-check:[...][1] : (13, 14) [Type: tuple$<i32, i32>]
|
||||
// cdb-command:dx internal_padding1.__1,d
|
||||
// cdb-check:internal_padding1.__1,d [...]: (13, 14) [Type: tuple<i32, i32>]
|
||||
// cdb-check:internal_padding1.__1,d [...]: (13, 14) [Type: tuple$<i32, i32>]
|
||||
// cdb-check:[...][0] : 13 [Type: [...]]
|
||||
// cdb-check:[...][1] : 14 [Type: [...]]
|
||||
// cdb-command:dx internal_padding2,d
|
||||
// cdb-check:internal_padding2,d [...]: (15, (16, 17)) [Type: tuple<i16, tuple<i16, i32>>]
|
||||
// cdb-check:internal_padding2,d [...]: (15, (16, 17)) [Type: tuple$<i16, tuple$<i16, i32> >]
|
||||
// cdb-check:[...][0] : 15 [Type: [...]]
|
||||
// cdb-check:[...][1] : (16, 17) [Type: tuple<i16, i32>]
|
||||
// cdb-check:[...][1] : (16, 17) [Type: tuple$<i16, i32>]
|
||||
// cdb-command:dx internal_padding2.__1,d
|
||||
// cdb-check:internal_padding2.__1,d [...]: (16, 17) [Type: tuple<i16, i32>]
|
||||
// cdb-check:internal_padding2.__1,d [...]: (16, 17) [Type: tuple$<i16, i32>]
|
||||
// cdb-check:[...][0] : 16 [Type: [...]]
|
||||
// cdb-check:[...][1] : 17 [Type: [...]]
|
||||
|
||||
// cdb-command:dx padding_at_end1,d
|
||||
// cdb-check:padding_at_end1,d [...]: (18, (19, 20)) [Type: tuple<i32, tuple<i32, i16>>]
|
||||
// cdb-check:padding_at_end1,d [...]: (18, (19, 20)) [Type: tuple$<i32, tuple$<i32, i16> >]
|
||||
// cdb-check:[...][0] : 18 [Type: [...]]
|
||||
// cdb-check:[...][1] : (19, 20) [Type: tuple<i32, i16>]
|
||||
// cdb-check:[...][1] : (19, 20) [Type: tuple$<i32, i16>]
|
||||
// cdb-command:dx padding_at_end1.__1,d
|
||||
// cdb-check:padding_at_end1.__1,d [...][Type: tuple<i32, i16>]
|
||||
// cdb-check:padding_at_end1.__1,d [...][Type: tuple$<i32, i16>]
|
||||
// cdb-check:[...][0] : 19 [Type: [...]]
|
||||
// cdb-check:[...][1] : 20 [Type: [...]]
|
||||
// cdb-command:dx padding_at_end2,d
|
||||
// cdb-check:padding_at_end2,d [...]: ((21, 22), 23) [Type: tuple<tuple<i32, i16>, i32>]
|
||||
// cdb-check:[...][0] : (21, 22) [Type: tuple<i32, i16>]
|
||||
// cdb-check:padding_at_end2,d [...]: ((21, 22), 23) [Type: tuple$<tuple$<i32, i16>, i32>]
|
||||
// cdb-check:[...][0] : (21, 22) [Type: tuple$<i32, i16>]
|
||||
// cdb-check:[...][1] : 23 [Type: [...]]
|
||||
// cdb-command:dx padding_at_end2.__0,d
|
||||
// cdb-check:padding_at_end2.__0,d [...]: (21, 22) [Type: tuple<i32, i16>]
|
||||
// cdb-check:padding_at_end2.__0,d [...]: (21, 22) [Type: tuple$<i32, i16>]
|
||||
// cdb-check:[...][0] : 21 [Type: [...]]
|
||||
// cdb-check:[...][1] : 22 [Type: [...]]
|
||||
|
||||
|
|
17
src/test/debuginfo/type-names.cdb.js
Normal file
17
src/test/debuginfo/type-names.cdb.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Helper functions for running the type-names.rs test under CDB
|
||||
|
||||
// CDB exposes an "object model" via JavaScript that allows you to inspect debugging info - in this
|
||||
// case we want to ask the object model for the return and parameter types for a local variable
|
||||
// that is a function pointer to make sure that we are emitting the function pointer type in such a
|
||||
// way that CDB understands how to parse it.
|
||||
|
||||
"use strict";
|
||||
|
||||
function getFunctionDetails(name)
|
||||
{
|
||||
var localVariable = host.currentThread.Stack.Frames[0].LocalVariables[name];
|
||||
var functionPointerType = localVariable.targetType.genericArguments[0];
|
||||
var functionType = functionPointerType.baseType;
|
||||
host.diagnostics.debugLog("Return Type: ", functionType.functionReturnType, "\n");
|
||||
host.diagnostics.debugLog("Parameter Types: ", functionType.functionParameterTypes, "\n");
|
||||
}
|
|
@ -1,208 +1,268 @@
|
|||
// ignore-lldb
|
||||
// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
|
||||
|
||||
// GDB changed the way that it formatted Foreign types
|
||||
// min-gdb-version: 9.2
|
||||
|
||||
// compile-flags:-g
|
||||
|
||||
// === GDB TESTS ===================================================================================
|
||||
|
||||
// gdb-command:run
|
||||
|
||||
// STRUCTS
|
||||
// gdb-command:whatis simple_struct
|
||||
// gdbg-check:type = struct Struct1
|
||||
// gdbr-check:type = type_names::Struct1
|
||||
// gdb-check:type = type_names::Struct1
|
||||
|
||||
// gdb-command:whatis generic_struct1
|
||||
// gdbg-check:type = struct GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3>
|
||||
// gdbr-check:type = type_names::GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3>
|
||||
// gdb-check:type = type_names::GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3>
|
||||
|
||||
// gdb-command:whatis generic_struct2
|
||||
// gdbg-check:type = struct GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize>
|
||||
// gdbr-check:type = type_names::GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize>
|
||||
// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize>
|
||||
|
||||
// gdb-command:whatis mod_struct
|
||||
// gdbg-check:type = struct Struct2
|
||||
// gdbr-check:type = type_names::mod1::Struct2
|
||||
// gdb-check:type = type_names::mod1::Struct2
|
||||
|
||||
// ENUMS
|
||||
// gdb-command:whatis simple_enum_1
|
||||
// gdbg-check:type = union Enum1
|
||||
// gdbr-check:type = type_names::Enum1
|
||||
// gdb-check:type = type_names::Enum1
|
||||
|
||||
// gdb-command:whatis simple_enum_2
|
||||
// gdbg-check:type = union Enum1
|
||||
// gdbr-check:type = type_names::Enum1
|
||||
// gdb-check:type = type_names::Enum1
|
||||
|
||||
// gdb-command:whatis simple_enum_3
|
||||
// gdbg-check:type = union Enum2
|
||||
// gdbr-check:type = type_names::mod1::Enum2
|
||||
// gdb-check:type = type_names::mod1::Enum2
|
||||
|
||||
// gdb-command:whatis generic_enum_1
|
||||
// gdbg-check:type = union Enum3<type_names::mod1::Struct2>
|
||||
// gdbr-check:type = type_names::mod1::mod2::Enum3<type_names::mod1::Struct2>
|
||||
// gdb-check:type = type_names::mod1::mod2::Enum3
|
||||
|
||||
// gdb-command:whatis generic_enum_2
|
||||
// gdbg-check:type = union Enum3<type_names::Struct1>
|
||||
// gdbr-check:type = type_names::mod1::mod2::Enum3<type_names::Struct1>
|
||||
// gdb-check:type = type_names::mod1::mod2::Enum3
|
||||
|
||||
// TUPLES
|
||||
// gdb-command:whatis tuple1
|
||||
// gdbg-check:type = struct (u32, type_names::Struct1, type_names::mod1::mod2::Enum3<type_names::mod1::Struct2>)
|
||||
// gdbr-check:type = (u32, type_names::Struct1, type_names::mod1::mod2::Enum3<type_names::mod1::Struct2>)
|
||||
// gdb-check:type = (u32, type_names::Struct1, type_names::mod1::mod2::Enum3<type_names::mod1::Struct2>)
|
||||
|
||||
// gdb-command:whatis tuple2
|
||||
// gdbg-check:type = struct ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char)
|
||||
// gdbr-check:type = ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char)
|
||||
// gdb-check:type = ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char)
|
||||
|
||||
// BOX
|
||||
// gdb-command:whatis box1
|
||||
// gdbg-check:type = struct (alloc::boxed::Box<f32>, i32)
|
||||
// gdbr-check:type = (alloc::boxed::Box<f32>, i32)
|
||||
// gdb-check:type = (alloc::boxed::Box<f32, alloc::alloc::Global>, i32)
|
||||
|
||||
// gdb-command:whatis box2
|
||||
// gdbg-check:type = struct (alloc::boxed::Box<type_names::mod1::mod2::Enum3<f32>>, i32)
|
||||
// gdbr-check:type = (alloc::boxed::Box<type_names::mod1::mod2::Enum3<f32>>, i32)
|
||||
// gdb-check:type = (alloc::boxed::Box<type_names::mod1::mod2::Enum3<f32>, alloc::alloc::Global>, i32)
|
||||
|
||||
// REFERENCES
|
||||
// gdb-command:whatis ref1
|
||||
// gdbg-check:type = struct (&type_names::Struct1, i32)
|
||||
// gdbr-check:type = (&type_names::Struct1, i32)
|
||||
// gdb-check:type = (&type_names::Struct1, i32)
|
||||
|
||||
// gdb-command:whatis ref2
|
||||
// gdbg-check:type = struct (&type_names::GenericStruct<char, type_names::Struct1>, i32)
|
||||
// gdbr-check:type = (&type_names::GenericStruct<char, type_names::Struct1>, i32)
|
||||
// gdb-check:type = (&type_names::GenericStruct<char, type_names::Struct1>, i32)
|
||||
|
||||
// gdb-command:whatis mut_ref1
|
||||
// gdbg-check:type = struct (&mut type_names::Struct1, i32)
|
||||
// gdbr-check:type = (&mut type_names::Struct1, i32)
|
||||
// gdb-check:type = (&mut type_names::Struct1, i32)
|
||||
|
||||
// gdb-command:whatis mut_ref2
|
||||
// gdbg-check:type = struct (&mut type_names::GenericStruct<type_names::mod1::Enum2, f64>, i32)
|
||||
// gdbr-check:type = (&mut type_names::GenericStruct<type_names::mod1::Enum2, f64>, i32)
|
||||
// gdb-check:type = (&mut type_names::GenericStruct<type_names::mod1::Enum2, f64>, i32)
|
||||
|
||||
// RAW POINTERS
|
||||
// gdb-command:whatis mut_ptr1
|
||||
// gdbg-check:type = struct (*mut type_names::Struct1, isize)
|
||||
// gdbr-check:type = (*mut type_names::Struct1, isize)
|
||||
// gdb-check:type = (*mut type_names::Struct1, isize)
|
||||
|
||||
// gdb-command:whatis mut_ptr2
|
||||
// gdbg-check:type = struct (*mut isize, isize)
|
||||
// gdbr-check:type = (*mut isize, isize)
|
||||
// gdb-check:type = (*mut isize, isize)
|
||||
|
||||
// gdb-command:whatis mut_ptr3
|
||||
// gdbg-check:type = struct (*mut type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
|
||||
// gdbr-check:type = (*mut type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
|
||||
// gdb-check:type = (*mut type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
|
||||
|
||||
// gdb-command:whatis const_ptr1
|
||||
// gdbg-check:type = struct (*const type_names::Struct1, isize)
|
||||
// gdbr-check:type = (*const type_names::Struct1, isize)
|
||||
// gdb-check:type = (*const type_names::Struct1, isize)
|
||||
|
||||
// gdb-command:whatis const_ptr2
|
||||
// gdbg-check:type = struct (*const isize, isize)
|
||||
// gdbr-check:type = (*const isize, isize)
|
||||
// gdb-check:type = (*const isize, isize)
|
||||
|
||||
// gdb-command:whatis const_ptr3
|
||||
// gdbg-check:type = struct (*const type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
|
||||
// gdbr-check:type = (*const type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
|
||||
// gdb-check:type = (*const type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
|
||||
|
||||
// VECTORS
|
||||
// gdb-command:whatis fixed_size_vec1
|
||||
// gdbg-check:type = struct ([type_names::Struct1; 3], i16)
|
||||
// gdbr-check:type = ([type_names::Struct1; 3], i16)
|
||||
// gdb-check:type = ([type_names::Struct1; 3], i16)
|
||||
|
||||
// gdb-command:whatis fixed_size_vec2
|
||||
// gdbg-check:type = struct ([usize; 3], i16)
|
||||
// gdbr-check:type = ([usize; 3], i16)
|
||||
// gdb-check:type = ([usize; 3], i16)
|
||||
|
||||
// gdb-command:whatis slice1
|
||||
// gdbg-check:type = struct &[usize]
|
||||
// gdbr-check:type = &[usize]
|
||||
// gdb-check:type = &[usize]
|
||||
|
||||
// gdb-command:whatis slice2
|
||||
// gdbg-check:type = struct &[type_names::mod1::Enum2]
|
||||
// gdbr-check:type = &[type_names::mod1::Enum2]
|
||||
// gdb-check:type = &[type_names::mod1::Enum2]
|
||||
|
||||
// TRAITS
|
||||
// gdb-command:whatis box_trait
|
||||
// gdbg-check:type = struct Box<Trait1>
|
||||
// gdbr-check:type = type_names::Box<Trait1>
|
||||
// gdb-check:type = alloc::boxed::Box<dyn type_names::Trait1, alloc::alloc::Global>
|
||||
|
||||
// gdb-command:whatis ref_trait
|
||||
// gdbg-check:type = struct &Trait1
|
||||
// gdbr-check:type = type_names::&Trait1
|
||||
// gdb-check:type = &dyn type_names::Trait1
|
||||
|
||||
// gdb-command:whatis mut_ref_trait
|
||||
// gdbg-check:type = struct &mut Trait1
|
||||
// gdbr-check:type = type_names::&mut Trait1
|
||||
// gdb-check:type = &mut dyn type_names::Trait1
|
||||
|
||||
// gdb-command:whatis generic_box_trait
|
||||
// gdbg-check:type = struct Box<Trait2<i32, type_names::mod1::Struct2>>
|
||||
// gdbr-check:type = type_names::Box<Trait2<i32, type_names::mod1::Struct2>>
|
||||
// gdb-check:type = alloc::boxed::Box<dyn type_names::Trait2<i32, type_names::mod1::Struct2>, alloc::alloc::Global>
|
||||
|
||||
// gdb-command:whatis generic_ref_trait
|
||||
// gdbg-check:type = struct &Trait2<type_names::Struct1, type_names::Struct1>
|
||||
// gdbr-check:type = type_names::&Trait2<type_names::Struct1, type_names::Struct1>
|
||||
// gdb-check:type = &dyn type_names::Trait2<type_names::Struct1, type_names::Struct1>
|
||||
|
||||
// gdb-command:whatis generic_mut_ref_trait
|
||||
// gdbg-check:type = struct &mut Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize>>
|
||||
// gdbr-check:type = type_names::&mut Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize>>
|
||||
// gdb-check:type = &mut dyn type_names::Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize>>
|
||||
|
||||
// gdb-command:whatis no_principal_trait
|
||||
// gdb-check:type = alloc::boxed::Box<dyn core::marker::Send + core::marker::Sync, alloc::alloc::Global>
|
||||
|
||||
// BARE FUNCTIONS
|
||||
// gdb-command:whatis rust_fn
|
||||
// gdbg-check:type = struct (fn(core::option::Option<isize>, core::option::Option<&type_names::mod1::Struct2>), usize)
|
||||
// gdbr-check:type = (fn(core::option::Option<isize>, core::option::Option<&type_names::mod1::Struct2>), usize)
|
||||
// gdb-check:type = (fn(core::option::Option<isize>, core::option::Option<&type_names::mod1::Struct2>), usize)
|
||||
|
||||
// gdb-command:whatis extern_c_fn
|
||||
// gdbg-check:type = struct (extern "C" fn(isize), usize)
|
||||
// gdbr-check:type = (extern "C" fn(isize), usize)
|
||||
// gdb-check:type = (extern "C" fn(isize), usize)
|
||||
|
||||
// gdb-command:whatis unsafe_fn
|
||||
// gdbg-check:type = struct (unsafe fn(core::result::Result<char, f64>), usize)
|
||||
// gdbr-check:type = (unsafe fn(core::result::Result<char, f64>), usize)
|
||||
|
||||
// gdb-command:whatis extern_stdcall_fn
|
||||
// gdbg-check:type = struct (extern "stdcall" fn(), usize)
|
||||
// gdbr-check:type = (extern "stdcall" fn(), usize)
|
||||
// gdb-check:type = (unsafe fn(core::result::Result<char, f64>), usize)
|
||||
|
||||
// gdb-command:whatis rust_fn_with_return_value
|
||||
// gdbg-check:type = struct (fn(f64) -> usize, usize)
|
||||
// gdbr-check:type = (fn(f64) -> usize, usize)
|
||||
// gdb-check:type = (fn(f64) -> usize, usize)
|
||||
|
||||
// gdb-command:whatis extern_c_fn_with_return_value
|
||||
// gdbg-check:type = struct (extern "C" fn() -> type_names::Struct1, usize)
|
||||
// gdbr-check:type = (extern "C" fn() -> type_names::Struct1, usize)
|
||||
// gdb-check:type = (extern "C" fn() -> type_names::Struct1, usize)
|
||||
|
||||
// gdb-command:whatis unsafe_fn_with_return_value
|
||||
// gdbg-check:type = struct (unsafe fn(type_names::GenericStruct<u16, u8>) -> type_names::mod1::Struct2, usize)
|
||||
// gdbr-check:type = (unsafe fn(type_names::GenericStruct<u16, u8>) -> type_names::mod1::Struct2, usize)
|
||||
|
||||
// gdb-command:whatis extern_stdcall_fn_with_return_value
|
||||
// gdbg-check:type = struct (extern "stdcall" fn(alloc::boxed::Box<isize>) -> usize, usize)
|
||||
// gdbr-check:type = (extern "stdcall" fn(alloc::boxed::Box<isize>) -> usize, usize)
|
||||
// gdb-check:type = (unsafe fn(type_names::GenericStruct<u16, u8>) -> type_names::mod1::Struct2, usize)
|
||||
|
||||
// gdb-command:whatis generic_function_int
|
||||
// gdbg-check:type = struct (fn(isize) -> isize, usize)
|
||||
// gdbr-check:type = (fn(isize) -> isize, usize)
|
||||
// gdb-check:type = (fn(isize) -> isize, usize)
|
||||
|
||||
// gdb-command:whatis generic_function_struct3
|
||||
// gdbg-check:type = struct (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize)
|
||||
// gdbr-check:type = (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize)
|
||||
// gdb-check:type = (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize)
|
||||
|
||||
// gdb-command:whatis variadic_function
|
||||
// gdbg-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> isize, usize)
|
||||
// gdbr-check:type = (unsafe extern "C" fn(*const u8, ...) -> isize, usize)
|
||||
// gdb-check:type = (unsafe extern "C" fn(*const u8, ...) -> isize, usize)
|
||||
|
||||
// CLOSURES
|
||||
// gdb-command:whatis closure1
|
||||
// gdbg-check:type = struct (closure, usize)
|
||||
// gdbr-check:type = (closure, usize)
|
||||
// gdb-check:type = (type_names::main::{closure#0}, usize)
|
||||
|
||||
// gdb-command:whatis closure2
|
||||
// gdbg-check:type = struct (closure, usize)
|
||||
// gdbr-check:type = (closure, usize)
|
||||
// gdb-check:type = (type_names::main::{closure#1}, usize)
|
||||
|
||||
// FOREIGN TYPES
|
||||
// gdb-command:whatis foreign1
|
||||
// gdb-check:type = *mut ForeignType1
|
||||
|
||||
// gdb-command:whatis foreign2
|
||||
// gdb-check:type = *mut ForeignType2
|
||||
|
||||
// === CDB TESTS ==================================================================================
|
||||
|
||||
// cdb-command: g
|
||||
|
||||
// STRUCTS
|
||||
// 0-sized structs appear to be optimized away in some cases, so only check the structs that do
|
||||
// actually appear.
|
||||
// cdb-command:dv /t *_struct
|
||||
// cdb-check:struct type_names::GenericStruct<enum$<type_names::mod1::Enum2>, f64> mut_generic_struct = [...]
|
||||
|
||||
// ENUMS
|
||||
// cdb-command:dv /t *_enum_*
|
||||
// cdb-check:union enum$<type_names::Enum1> simple_enum_1 = [...]
|
||||
// cdb-check:union enum$<type_names::Enum1> simple_enum_2 = [...]
|
||||
// cdb-check:type_names::mod1::Enum2 simple_enum_3 = [...]
|
||||
// cdb-check:type_names::mod1::mod2::Enum3 generic_enum_1 = [...]
|
||||
// cdb-check:type_names::mod1::mod2::Enum3 generic_enum_2 = [...]
|
||||
|
||||
// TUPLES
|
||||
// cdb-command:dv /t tuple*
|
||||
// cdb-check:struct tuple$<u32, type_names::Struct1, enum$<type_names::mod1::mod2::Enum3<type_names::mod1::Struct2> > > tuple1 = [...]
|
||||
// cdb-check:struct tuple$<tuple$<type_names::Struct1, type_names::mod1::mod2::Struct3>, enum$<type_names::mod1::Enum2>, char> tuple2 = [...]
|
||||
|
||||
// BOX
|
||||
// cdb-command:dv /t box*
|
||||
// cdb-check:struct tuple$<alloc::boxed::Box<f32, alloc::alloc::Global>, i32> box1 = [...]
|
||||
// cdb-check:struct tuple$<alloc::boxed::Box<enum$<type_names::mod1::mod2::Enum3<f32> >, alloc::alloc::Global>, i32> box2 = [...]
|
||||
|
||||
// REFERENCES
|
||||
// cdb-command:dv /t *ref*
|
||||
// cdb-check:struct tuple$<ref$<type_names::Struct1>, i32> ref1 = [...]
|
||||
// cdb-check:struct tuple$<ref$<type_names::GenericStruct<char, type_names::Struct1> >, i32> ref2 = [...]
|
||||
// cdb-check:struct tuple$<ref_mut$<type_names::Struct1>, i32> mut_ref1 = [...]
|
||||
// cdb-check:struct tuple$<ref_mut$<type_names::GenericStruct<enum$<type_names::mod1::Enum2>, f64> >, i32> mut_ref2 = [...]
|
||||
|
||||
// RAW POINTERS
|
||||
// cdb-command:dv /t *_ptr*
|
||||
// cdb-check:struct tuple$<ptr_mut$<type_names::Struct1>, isize> mut_ptr1 = [...]
|
||||
// cdb-check:struct tuple$<ptr_mut$<isize>, isize> mut_ptr2 = [...]
|
||||
// cdb-check:struct tuple$<ptr_mut$<enum$<type_names::mod1::mod2::Enum3<type_names::Struct1> > >, isize> mut_ptr3 = [...]
|
||||
// cdb-check:struct tuple$<ptr_const$<type_names::Struct1>, isize> const_ptr1 = [...]
|
||||
// cdb-check:struct tuple$<ptr_const$<isize>, isize> const_ptr2 = [...]
|
||||
// cdb-check:struct tuple$<ptr_const$<enum$<type_names::mod1::mod2::Enum3<type_names::Struct1> > >, isize> const_ptr3 = [...]
|
||||
|
||||
// VECTORS
|
||||
// cdb-command:dv /t *vec*
|
||||
// cdb-check:struct tuple$<array$<type_names::Struct1,3>, i16> fixed_size_vec1 = [...]
|
||||
// cdb-check:struct tuple$<array$<usize,3>, i16> fixed_size_vec2 = [...]
|
||||
// cdb-check:struct alloc::vec::Vec<usize, alloc::alloc::Global> vec1 = [...]
|
||||
// cdb-check:struct alloc::vec::Vec<enum$<type_names::mod1::Enum2>, alloc::alloc::Global> vec2 = [...]
|
||||
// cdb-command:dv /t slice*
|
||||
// cdb-check:struct slice$<usize> slice1 = [...]
|
||||
// cdb-check:struct slice$<enum$<type_names::mod1::Enum2> > slice2 = [...]
|
||||
|
||||
// TRAITS
|
||||
// cdb-command:dv /t *_trait
|
||||
// cdb-check:struct ref_mut$<dyn$<type_names::Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize> > > > generic_mut_ref_trait = [...]
|
||||
// cdb-check:struct ref$<dyn$<type_names::Trait2<type_names::Struct1, type_names::Struct1> > > generic_ref_trait = [...]
|
||||
// cdb-check:struct alloc::boxed::Box<dyn$<type_names::Trait2<i32, type_names::mod1::Struct2> >, alloc::alloc::Global> generic_box_trait = [...]
|
||||
// cdb-check:struct alloc::boxed::Box<dyn$<type_names::Trait1>, alloc::alloc::Global> box_trait = [...]
|
||||
// cdb-check:struct ref$<dyn$<type_names::Trait1> > ref_trait = [...]
|
||||
// cdb-check:struct ref_mut$<dyn$<type_names::Trait1> > mut_ref_trait = [...]
|
||||
// cdb-check:struct alloc::boxed::Box<dyn$<core::marker::Send, core::marker::Sync>, alloc::alloc::Global> no_principal_trait = [...]
|
||||
// cdb-check:struct ref$<dyn$<type_names::Trait3> > has_associated_type_trait = struct ref$<dyn$<type_names::Trait3> >
|
||||
|
||||
// BARE FUNCTIONS
|
||||
// cdb-command:dv /t *_fn*
|
||||
// cdb-check:struct tuple$<type_names::mod1::Struct2 (*)(type_names::GenericStruct<u16, u8>), usize> unsafe_fn_with_return_value = [...]
|
||||
// cdb-check:struct tuple$<type_names::Struct1 (*)(), usize> extern_c_fn_with_return_value = [...]
|
||||
// cdb-check:struct tuple$<usize (*)(f64), usize> rust_fn_with_return_value = [...]
|
||||
// cdb-check:struct tuple$<void (*)(enum$<core::result::Result<char, f64> >), usize> unsafe_fn = [...]
|
||||
// cdb-check:struct tuple$<void (*)(isize), usize> extern_c_fn = [...]
|
||||
// cdb-check:struct tuple$<void (*)(enum$<core::option::Option<isize> >, enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>), usize> rust_fn = [...]
|
||||
// cdb-command:dv /t *_function*
|
||||
// cdb-check:struct tuple$<isize (*)(ptr_const$<u8>, ...), usize> variadic_function = [...]
|
||||
// cdb-check:struct tuple$<type_names::mod1::mod2::Struct3 (*)(type_names::mod1::mod2::Struct3), usize> generic_function_struct3 = [...]
|
||||
// cdb-check:struct tuple$<isize (*)(isize), usize> generic_function_int = [...]
|
||||
// cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn")
|
||||
// cdb-check:Return Type: void
|
||||
// cdb-check:Parameter Types: enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>
|
||||
// cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn_with_return_value")
|
||||
// cdb-check:Return Type: usize
|
||||
// cdb-check:Parameter Types: f64
|
||||
// cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("extern_c_fn_with_return_value")
|
||||
// cdb-check:Return Type: type_names::Struct1
|
||||
// cdb-check:Parameter Types:
|
||||
|
||||
// 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 = [...]
|
||||
|
||||
// FOREIGN TYPES
|
||||
// cdb-command:dv /t foreign*
|
||||
// cdb-check:struct ForeignType2 * foreign2 = [...]
|
||||
// cdb-check:struct ForeignType1 * foreign1 = [...]
|
||||
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unused_variables)]
|
||||
#![feature(omit_gdb_pretty_printer_section)]
|
||||
#![omit_gdb_pretty_printer_section]
|
||||
#![feature(extern_types)]
|
||||
|
||||
use self::Enum1::{Variant1, Variant2};
|
||||
use std::marker::PhantomData;
|
||||
|
@ -216,6 +276,8 @@ enum Enum1 {
|
|||
Variant2(isize),
|
||||
}
|
||||
|
||||
extern { type ForeignType1; }
|
||||
|
||||
mod mod1 {
|
||||
pub use self::Enum2::{Variant1, Variant2};
|
||||
pub struct Struct2;
|
||||
|
@ -234,6 +296,8 @@ mod mod1 {
|
|||
Variant2(T),
|
||||
}
|
||||
}
|
||||
|
||||
extern { pub type ForeignType2; }
|
||||
}
|
||||
|
||||
trait Trait1 {
|
||||
|
@ -242,14 +306,20 @@ trait Trait1 {
|
|||
trait Trait2<T1, T2> {
|
||||
fn dummy(&self, _: T1, _: T2) {}
|
||||
}
|
||||
trait Trait3 {
|
||||
type AssocType;
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
|
||||
impl Trait1 for isize {}
|
||||
impl<T1, T2> Trait2<T1, T2> for isize {}
|
||||
impl Trait3 for isize {
|
||||
type AssocType = isize;
|
||||
}
|
||||
|
||||
fn rust_fn(_: Option<isize>, _: Option<&mod1::Struct2>) {}
|
||||
extern "C" fn extern_c_fn(_: isize) {}
|
||||
unsafe fn unsafe_fn(_: Result<char, f64>) {}
|
||||
extern "stdcall" fn extern_stdcall_fn() {}
|
||||
|
||||
fn rust_fn_with_return_value(_: f64) -> usize {
|
||||
4
|
||||
|
@ -260,9 +330,6 @@ extern "C" fn extern_c_fn_with_return_value() -> Struct1 {
|
|||
unsafe fn unsafe_fn_with_return_value(_: GenericStruct<u16, u8>) -> mod1::Struct2 {
|
||||
mod1::Struct2
|
||||
}
|
||||
extern "stdcall" fn extern_stdcall_fn_with_return_value(_: Box<isize>) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn generic_function<T>(x: T) -> T {
|
||||
x
|
||||
|
@ -333,28 +400,28 @@ fn main() {
|
|||
let slice2 = &*vec2;
|
||||
|
||||
// Trait Objects
|
||||
let box_trait = (box 0_isize) as Box<Trait1>;
|
||||
let ref_trait = &0_isize as &Trait1;
|
||||
let box_trait = (box 0_isize) as Box<dyn Trait1>;
|
||||
let ref_trait = &0_isize as &dyn Trait1;
|
||||
let mut mut_int1 = 0_isize;
|
||||
let mut_ref_trait = (&mut mut_int1) as &mut Trait1;
|
||||
let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1;
|
||||
let no_principal_trait = (box 0_isize) as Box<dyn Send + Sync>;
|
||||
let has_associated_type_trait = &0_isize as &dyn Trait3<AssocType = isize>;
|
||||
|
||||
let generic_box_trait = (box 0_isize) as Box<Trait2<i32, mod1::Struct2>>;
|
||||
let generic_ref_trait = (&0_isize) as &Trait2<Struct1, Struct1>;
|
||||
let generic_box_trait = (box 0_isize) as Box<dyn Trait2<i32, mod1::Struct2>>;
|
||||
let generic_ref_trait = (&0_isize) as &dyn Trait2<Struct1, Struct1>;
|
||||
|
||||
let mut generic_mut_ref_trait_impl = 0_isize;
|
||||
let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl)
|
||||
as &mut Trait2<mod1::mod2::Struct3, GenericStruct<usize, isize>>;
|
||||
as &mut dyn Trait2<mod1::mod2::Struct3, GenericStruct<usize, isize>>;
|
||||
|
||||
// Bare Functions
|
||||
let rust_fn = (rust_fn, 0_usize);
|
||||
let extern_c_fn = (extern_c_fn, 0_usize);
|
||||
let unsafe_fn = (unsafe_fn, 0_usize);
|
||||
let extern_stdcall_fn = (extern_stdcall_fn, 0_usize);
|
||||
|
||||
let rust_fn_with_return_value = (rust_fn_with_return_value, 0_usize);
|
||||
let extern_c_fn_with_return_value = (extern_c_fn_with_return_value, 0_usize);
|
||||
let unsafe_fn_with_return_value = (unsafe_fn_with_return_value, 0_usize);
|
||||
let extern_stdcall_fn_with_return_value = (extern_stdcall_fn_with_return_value, 0_usize);
|
||||
|
||||
let generic_function_int = (generic_function::<isize>, 0_usize);
|
||||
let generic_function_struct3 = (generic_function::<mod1::mod2::Struct3>, 0_usize);
|
||||
|
@ -370,6 +437,10 @@ fn main() {
|
|||
let closure1 = (|x: isize| {}, 0_usize);
|
||||
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 };
|
||||
|
||||
zzz(); // #break
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}::closure-0]
|
||||
// cdb-check:nested_closure [Type: var_captured_in_nested_closure::main::closure$0::closure$0]
|
||||
|
||||
// cdb-command: g
|
||||
|
||||
|
|
|
@ -778,6 +778,14 @@ impl<'test> TestCx<'test> {
|
|||
script_str.push_str("version\n"); // List CDB (and more) version info in test output
|
||||
script_str.push_str(".nvlist\n"); // List loaded `*.natvis` files, bulk of custom MSVC debug
|
||||
|
||||
// If a .js file exists next to the source file being tested, then this is a JavaScript
|
||||
// debugging extension that needs to be loaded.
|
||||
let mut js_extension = self.testpaths.file.clone();
|
||||
js_extension.set_extension("cdb.js");
|
||||
if js_extension.exists() {
|
||||
script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy()));
|
||||
}
|
||||
|
||||
// Set breakpoints on every line that contains the string "#break"
|
||||
let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
|
||||
for line in &breakpoint_lines {
|
||||
|
@ -2329,13 +2337,17 @@ impl<'test> TestCx<'test> {
|
|||
// useful flag.
|
||||
//
|
||||
// For now, though…
|
||||
if let Some(rev) = self.revision {
|
||||
let prefixes = format!("CHECK,{}", rev);
|
||||
if self.config.llvm_version.unwrap_or(0) >= 130000 {
|
||||
filecheck.args(&["--allow-unused-prefixes", "--check-prefixes", &prefixes]);
|
||||
} else {
|
||||
filecheck.args(&["--check-prefixes", &prefixes]);
|
||||
}
|
||||
let prefix_for_target =
|
||||
if self.config.target.contains("msvc") { "MSVC" } else { "NONMSVC" };
|
||||
let prefixes = if let Some(rev) = self.revision {
|
||||
format!("CHECK,{},{}", prefix_for_target, rev)
|
||||
} else {
|
||||
format!("CHECK,{}", prefix_for_target)
|
||||
};
|
||||
if self.config.llvm_version.unwrap_or(0) >= 130000 {
|
||||
filecheck.args(&["--allow-unused-prefixes", "--check-prefixes", &prefixes]);
|
||||
} else {
|
||||
filecheck.args(&["--check-prefixes", &prefixes]);
|
||||
}
|
||||
self.compose_and_run(filecheck, "", None, None)
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[
|
|||
"// error-pattern",
|
||||
"// gdb",
|
||||
"// lldb",
|
||||
"// cdb",
|
||||
"// normalize-stderr-test",
|
||||
];
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue