From aac8a885520854e4b60ea5733b8b06f9e0cc1fcc Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 24 Jun 2021 10:36:28 -0700 Subject: [PATCH] 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. * Include a `$` in all synthetic types as this is a legal character for C++, but not Rust (thus we avoid collisions with user types). --- .../src/debuginfo/metadata.rs | 37 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 27 +- .../src/debuginfo/namespace.rs | 21 +- .../src/debuginfo/type_names.rs | 372 +++++++++++++----- src/etc/natvis/intrinsic.natvis | 26 +- src/etc/natvis/libstd.natvis | 2 +- src/test/codegen/async-fn-debug-msvc.rs | 2 +- src/test/codegen/async-fn-debug.rs | 2 +- src/test/codegen/fn-impl-trait-self.rs | 3 +- src/test/codegen/generator-debug-msvc.rs | 2 +- src/test/codegen/generator-debug.rs | 2 +- src/test/debuginfo/basic-types.rs | 44 ++- src/test/debuginfo/function-names.rs | 175 ++++++++ src/test/debuginfo/generator-objects.rs | 16 +- src/test/debuginfo/generic-struct.rs | 21 + src/test/debuginfo/issue-57822.rs | 8 +- src/test/debuginfo/msvc-pretty-enums.rs | 37 +- src/test/debuginfo/mutex.rs | 3 +- src/test/debuginfo/pretty-std.rs | 10 +- src/test/debuginfo/rc_arc.rs | 3 +- src/test/debuginfo/result-types.rs | 4 +- src/test/debuginfo/simple-tuple.rs | 14 +- src/test/debuginfo/thread.rs | 4 +- src/test/debuginfo/tuple-in-tuple.rs | 42 +- src/test/debuginfo/type-names.cdb.js | 17 + src/test/debuginfo/type-names.rs | 289 +++++++++----- .../var-captured-in-nested-closure.rs | 2 +- src/tools/compiletest/src/runtest.rs | 26 +- src/tools/tidy/src/style.rs | 1 + 29 files changed, 855 insertions(+), 357 deletions(-) create mode 100644 src/test/debuginfo/function-names.rs create mode 100644 src/test/debuginfo/type-names.cdb.js diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1e70664e64d..0e42931b29a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -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, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 2b99a2ebad9..8375d4c7ca5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -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); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index 9945d4f4282..1cbf5386996 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -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) ) }; diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 7b4b0821c4b..2684335d73d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -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(""); + output.push_str(if cpp_like_names { + "recursive_type$" + } else { + "" + }); 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>, - ) { - 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>, +) { + 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('>'); } diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 89280149a03..cf887ffb0c0 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -15,7 +15,7 @@ - + {{ len={length} }} length @@ -25,23 +25,23 @@ - + () - + ({__0}) __0 - + ({__0}, {__1}) __0 __1 - + ({__0}, {__1}, {__2}) __0 @@ -49,7 +49,7 @@ __2 - + ({__0}, {__1}, {__2}, {__3}) __0 @@ -58,7 +58,7 @@ __3 - + ({__0}, {__1}, {__2}, {__3}, {__4}) __0 @@ -68,7 +68,7 @@ __4 - + ({__0}, {__1}, {__2}, {__3}, {__4}, {__5}) __0 @@ -79,7 +79,7 @@ __5 - + ({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}) __0 @@ -91,7 +91,7 @@ __6 - + ({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}) __0 @@ -104,7 +104,7 @@ __7 - + ({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}, {__8}) __0 @@ -118,7 +118,7 @@ __8 - + ({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}, {__8}, {__9}) __0 @@ -133,7 +133,7 @@ __9 - + ({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}, {__8}, {__9}, ...) __0 diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index 2c05f9d7c12..3ccd2e9c30e 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -41,7 +41,7 @@ n-- - ((tuple<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__1 + ((tuple$<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__1 i++ diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index e410180bfff..8efa1b15b3f 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -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, diff --git a/src/test/codegen/async-fn-debug.rs b/src/test/codegen/async-fn-debug.rs index 7de115f7e91..39319a3ea72 100644 --- a/src/test/codegen/async-fn-debug.rs +++ b/src/test/codegen/async-fn-debug.rs @@ -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]*]] diff --git a/src/test/codegen/fn-impl-trait-self.rs b/src/test/codegen/fn-impl-trait-self.rs index f9113d50197..4bd811bed10 100644 --- a/src/test/codegen/fn-impl-trait-self.rs +++ b/src/test/codegen/fn-impl-trait-self.rs @@ -1,7 +1,8 @@ // compile-flags: -g // // CHECK-LABEL: @main -// CHECK: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> ",{{.*}} +// MSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "recursive_type$ (*)()",{{.*}} +// NONMSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> ",{{.*}} // // CHECK: {{.*}}DISubroutineType{{.*}} // CHECK: {{.*}}DIBasicType(name: "", encoding: DW_ATE_unsigned) diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 7edb07d224c..e2ba4ad3089 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -21,7 +21,7 @@ fn generator_test() -> impl Generator { // 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, diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs index 8b87a2f0646..ea324695c15 100644 --- a/src/test/codegen/generator-debug.rs +++ b/src/test/codegen/generator-debug.rs @@ -21,7 +21,7 @@ fn generator_test() -> impl Generator { // 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]*]] diff --git a/src/test/debuginfo/basic-types.rs b/src/test/debuginfo/basic-types.rs index 3721b87678d..83c7e0e9b6d 100644 --- a/src/test/debuginfo/basic-types.rs +++ b/src/test/debuginfo/basic-types.rs @@ -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 } diff --git a/src/test/debuginfo/function-names.rs b/src/test/debuginfo/function-names.rs new file mode 100644 index 00000000000..26317f5c3ff --- /dev/null +++ b/src/test/debuginfo/function-names.rs @@ -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::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 as function_names::TestTrait1>::trait_function(); +// gdb-check:[...]static fn as function_names::TestTrait1>::trait_function(); +// gdb-check:[...]static fn ::trait_function(); +// gdb-check:[...]static fn ::trait_function(); + +// Closure +// gdb-command:info functions -q function_names::.*::{{closure.* +// gdb-check:[...]static fn function_names::GenericStruct::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 (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::impl_function (void) + +// Trait implementations +// cdb-command:x a!function_names::*::trait_function* +// cdb-check:[...] a!function_names::impl$6::trait_function (void) +// cdb-check:[...] a!function_names::impl$3::trait_function (void) +// cdb-check:[...] a!function_names::impl$1::trait_function (void) +// cdb-check:[...] a!function_names::impl$5::trait_function3 (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 (void) +// cdb-check:[...] a!function_names::impl$2::impl_function::closure$0 (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::::impl_function(); + + // Trait implementations + TestStruct1::trait_function(); + Mod1::TestStruct2::trait_function(); + GenericStruct::::trait_function(); + GenericStruct::<[i32; 1], f32>::trait_function(); + GenericStruct::::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(std::marker::PhantomData<(T1, T2)>); + +// Generic implementation +impl GenericStruct { + pub fn impl_function() { + // Closure in a generic implementation + let closure = || { TestStruct1 }; + closure(); + } +} + +// Generic trait implementation +impl TestTrait1 for GenericStruct { + 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 TestTrait3 for GenericStruct { + type AssocType = T::AssocType; + fn trait_function3() {} +} + +// Generic trait implementation with const generics +impl TestTrait1 for GenericStruct<[T; N], f32> { + fn trait_function() {} +} + +// Generic function +fn generic_func(value: T) -> T { + // Closure in a generic function + let closure = || { TestStruct1 }; + closure(); + + value +} diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index 1beed1c835d..7ac3304aa96 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -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] diff --git a/src/test/debuginfo/generic-struct.rs b/src/test/debuginfo/generic-struct.rs index 170a610c621..c0135de1219 100644 --- a/src/test/debuginfo/generic-struct.rs +++ b/src/test/debuginfo/generic-struct.rs @@ -39,6 +39,27 @@ // lldbg-check:[...]$3 = AGenericStruct> { key: 6.5, value: AGenericStruct { key: 7, value: 8.5 } } // lldbr-check:(generic_struct::AGenericStruct>) float_int_float = AGenericStruct> { key: 6.5, value: AGenericStruct { key: 7, value: 8.5 } } +// === CDB TESTS =================================================================================== + +// cdb-command:g + +// cdb-command:dx int_int +// cdb-check:int_int [Type: generic_struct::AGenericStruct] +// 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] +// 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] +// 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 >] +// cdb-check:[...]key : 6.500000 [Type: double] +// cdb-check:[...]value [Type: generic_struct::AGenericStruct] + #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/issue-57822.rs b/src/test/debuginfo/issue-57822.rs index 6b2b12edda5..f6d2146fe11 100644 --- a/src/test/debuginfo/issue-57822.rs +++ b/src/test/debuginfo/issue-57822.rs @@ -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] diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index 550cc66f389..63555116b94 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -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$>, 2, 16, Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$>, 2, 16, Some>::Some] +// cdb-check:a,! : Some({...}) [Type: enum$ >, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 2, 16, Some>::Some] // cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$>, 2, 16, Some>::Discriminant$] +// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$ >, 2, 16, Some>::Discriminant$] // cdb-command: dx -r2 b,! -// cdb-check:b,! [Type: enum$>, 2, 16, Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$>, 2, 16, Some>::Some] +// cdb-check:b,! : None [Type: enum$ >, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 2, 16, Some>::Some] // cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum] -// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$>, 2, 16, Some>::Discriminant$] +// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$ >, 2, 16, Some>::Discriminant$] // cdb-command: dx -r2 c,! -// cdb-check:c,! [Type: enum$] +// cdb-check:c,! : Tag1 [Type: enum$] // cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum] // cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$::Discriminant$] // cdb-command: dx -r2 d,! -// cdb-check:d,! [Type: enum$] +// cdb-check:d,! : Data({...}) [Type: enum$] // cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] // cdb-check: [+0x000] discriminant : 0x10 [Type: enum$::Discriminant$] // cdb-command: dx -r2 e,! -// cdb-check:e,! [Type: enum$] +// cdb-check:e,! : Tag2 [Type: enum$] // cdb-check: [+0x000] dataful_variant [Type: enum$::Data] // cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum] // cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$::Discriminant$] // cdb-command: dx -r2 f,! -// cdb-check:f,! [Type: enum$, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] +// cdb-check:f,! : Some({...}) [Type: enum$ >, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::Discriminant$] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$ >, 1, [...], Some>::Discriminant$] // cdb-command: dx -r2 g,! -// cdb-check:g,! [Type: enum$, 1, [...], Some>] -// cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] +// cdb-check:g,! : None [Type: enum$ >, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$ >, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *] -// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$, 1, [...], Some>::Discriminant$] +// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$ >, 1, [...], Some>::Discriminant$] // cdb-command: dx h -// cdb-check:h : Some [Type: enum$>] +// cdb-check:h : Some [Type: enum$ >] // 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$>] +// cdb-check:i : None [Type: enum$ >] // 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$, 1, [...], Some>] +// cdb-check:k,! : Some({...}) [Type: enum$, 1, [...], Some>] // cdb-check: [+0x000] dataful_variant [Type: enum$, 1, [...], Some>::Some] // cdb-check: [+0x000] __0 [Type: alloc::string::String] // cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::Discriminant$] diff --git a/src/test/debuginfo/mutex.rs b/src/test/debuginfo/mutex.rs index 969099359ab..40bea30f125 100644 --- a/src/test/debuginfo/mutex.rs +++ b/src/test/debuginfo/mutex.rs @@ -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$, enum$>, 0, 1, Poisoned>>>] +// cdb-check:lock,d : Ok [Type: enum$, enum$ >, 0, 1, Poisoned> > >] // cdb-check: [...] variant$ : Ok (0) [Type: core::result::Result] // cdb-check: [...] __0 [Type: std::sync::mutex::MutexGuard] diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index aeee1e6258d..f36003fbef0 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -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] +// cdb-check:slice,d : { len=4 } [Type: slice$] // 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$>] +// cdb-check:some : Some [Type: enum$ >] // 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$>] +// cdb-check:none : None [Type: enum$ >] // 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$, 1, [...], Some>] +// cdb-check:some_string : Some({...}) [Type: enum$, 1, [...], Some>] +// cdb-check: [...] __0 : "IAMA optional string!" [Type: alloc::string::String] #![allow(unused_variables)] use std::ffi::OsString; diff --git a/src/test/debuginfo/rc_arc.rs b/src/test/debuginfo/rc_arc.rs index 9f1e856ab42..6e558bd3c13 100644 --- a/src/test/debuginfo/rc_arc.rs +++ b/src/test/debuginfo/rc_arc.rs @@ -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] -// cdb-check: [...] ptr : [...] [Type: core::ptr::non_null::NonNull>] +// cdb-check: [...] ptr : [...] [Type: core::ptr::non_null::NonNull >] // cdb-command:dx a,d // cdb-check:a,d : 42 [Type: alloc::sync::Arc] diff --git a/src/test/debuginfo/result-types.rs b/src/test/debuginfo/result-types.rs index 18eae7f301f..a075c437c46 100644 --- a/src/test/debuginfo/result-types.rs +++ b/src/test/debuginfo/result-types.rs @@ -7,11 +7,11 @@ // cdb-command: g // cdb-command: dx x,d -// cdb-check:x,d : Ok [Type: enum$>] +// cdb-check:x,d : Ok [Type: enum$ >] // cdb-check: [...] __0 : -3 [Type: int] // cdb-command: dx y -// cdb-check:y : Err [Type: enum$>] +// cdb-check:y : Err [Type: enum$ >] // cdb-check: [...] __0 : "Some error message" [Type: str] fn main() diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index b7fcfeef090..9f4bf31f2c2 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -129,38 +129,38 @@ // cdb-command: g // cdb-command:dx noPadding8,d -// cdb-check:noPadding8,d [...]: (-100, 100) [Type: tuple] +// cdb-check:noPadding8,d [...]: (-100, 100) [Type: tuple$] // cdb-check:[...][0] : -100 [Type: [...]] // cdb-check:[...][1] : 100 [Type: [...]] // cdb-command:dx noPadding16,d -// cdb-check:noPadding16,d [...]: (0, 1, 2) [Type: tuple] +// cdb-check:noPadding16,d [...]: (0, 1, 2) [Type: tuple$] // 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] +// cdb-check:noPadding32,d [...]: (3, 4.5[...], 5) [Type: tuple$] // 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] +// cdb-check:noPadding64,d [...]: (6, 7.5[...], 8) [Type: tuple$] // 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] +// cdb-check:internalPadding1,d [...]: (9, 10) [Type: tuple$] // 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] +// cdb-check:internalPadding2,d [...]: (11, 12, 13, 14) [Type: tuple$] // 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] +// cdb-check:paddingAtEnd,d [...]: (15, 16) [Type: tuple$] // cdb-check:[...][0] : 15 [Type: [...]] // cdb-check:[...][1] : 16 [Type: [...]] diff --git a/src/test/debuginfo/thread.rs b/src/test/debuginfo/thread.rs index af35ad6af07..531c37a3421 100644 --- a/src/test/debuginfo/thread.rs +++ b/src/test/debuginfo/thread.rs @@ -9,8 +9,8 @@ // cdb-command:g // // cdb-command:dx join_handle,d -// cdb-check:join_handle,d [Type: std::thread::JoinHandle>] -// cdb-check: [...] __0 [Type: std::thread::JoinInner>] +// cdb-check:join_handle,d [Type: std::thread::JoinHandle >] +// cdb-check: [...] __0 [Type: std::thread::JoinInner >] // // cdb-command:dx t,d // cdb-check:t,d : [...] [Type: std::thread::Thread *] diff --git a/src/test/debuginfo/tuple-in-tuple.rs b/src/test/debuginfo/tuple-in-tuple.rs index 0447d8e9dde..fa6c579480e 100644 --- a/src/test/debuginfo/tuple-in-tuple.rs +++ b/src/test/debuginfo/tuple-in-tuple.rs @@ -65,64 +65,64 @@ // cdb-command: g // cdb-command:dx no_padding1,d -// cdb-check:no_padding1,d [...]: ((0, 1), 2, 3) [Type: tuple, u32, u32>] -// cdb-check:[...][0] : (0, 1) [Type: tuple] +// cdb-check:no_padding1,d [...]: ((0, 1), 2, 3) [Type: tuple$, u32, u32>] +// cdb-check:[...][0] : (0, 1) [Type: tuple$] // 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] +// cdb-check:no_padding1.__0,d [...]: (0, 1) [Type: tuple$] // 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>] +// cdb-check:no_padding2,d [...]: (4, (5, 6), 7) [Type: tuple$, u32>] // cdb-check:[...][0] : 4 [Type: [...]] -// cdb-check:[...][1] : (5, 6) [Type: tuple] +// cdb-check:[...][1] : (5, 6) [Type: tuple$] // cdb-check:[...][2] : 7 [Type: [...]] // cdb-command:dx no_padding2.__1,d -// cdb-check:no_padding2.__1,d [...]: (5, 6) [Type: tuple] +// cdb-check:no_padding2.__1,d [...]: (5, 6) [Type: tuple$] // 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>] +// cdb-check:no_padding3,d [...]: (8, 9, (10, 11)) [Type: tuple$ >] // cdb-check:[...][0] : 8 [Type: [...]] // cdb-check:[...][1] : 9 [Type: [...]] -// cdb-check:[...][2] : (10, 11) [Type: tuple] +// cdb-check:[...][2] : (10, 11) [Type: tuple$] // cdb-command:dx no_padding3.__2,d -// cdb-check:no_padding3.__2,d [...]: (10, 11) [Type: tuple] +// cdb-check:no_padding3.__2,d [...]: (10, 11) [Type: tuple$] // 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>] +// cdb-check:internal_padding1,d [...]: (12, (13, 14)) [Type: tuple$ >] // cdb-check:[...][0] : 12 [Type: [...]] -// cdb-check:[...][1] : (13, 14) [Type: tuple] +// cdb-check:[...][1] : (13, 14) [Type: tuple$] // cdb-command:dx internal_padding1.__1,d -// cdb-check:internal_padding1.__1,d [...]: (13, 14) [Type: tuple] +// cdb-check:internal_padding1.__1,d [...]: (13, 14) [Type: tuple$] // 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>] +// cdb-check:internal_padding2,d [...]: (15, (16, 17)) [Type: tuple$ >] // cdb-check:[...][0] : 15 [Type: [...]] -// cdb-check:[...][1] : (16, 17) [Type: tuple] +// cdb-check:[...][1] : (16, 17) [Type: tuple$] // cdb-command:dx internal_padding2.__1,d -// cdb-check:internal_padding2.__1,d [...]: (16, 17) [Type: tuple] +// cdb-check:internal_padding2.__1,d [...]: (16, 17) [Type: tuple$] // 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>] +// cdb-check:padding_at_end1,d [...]: (18, (19, 20)) [Type: tuple$ >] // cdb-check:[...][0] : 18 [Type: [...]] -// cdb-check:[...][1] : (19, 20) [Type: tuple] +// cdb-check:[...][1] : (19, 20) [Type: tuple$] // cdb-command:dx padding_at_end1.__1,d -// cdb-check:padding_at_end1.__1,d [...][Type: tuple] +// cdb-check:padding_at_end1.__1,d [...][Type: tuple$] // 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, i32>] -// cdb-check:[...][0] : (21, 22) [Type: tuple] +// cdb-check:padding_at_end2,d [...]: ((21, 22), 23) [Type: tuple$, i32>] +// cdb-check:[...][0] : (21, 22) [Type: tuple$] // cdb-check:[...][1] : 23 [Type: [...]] // cdb-command:dx padding_at_end2.__0,d -// cdb-check:padding_at_end2.__0,d [...]: (21, 22) [Type: tuple] +// cdb-check:padding_at_end2.__0,d [...]: (21, 22) [Type: tuple$] // cdb-check:[...][0] : 21 [Type: [...]] // cdb-check:[...][1] : 22 [Type: [...]] diff --git a/src/test/debuginfo/type-names.cdb.js b/src/test/debuginfo/type-names.cdb.js new file mode 100644 index 00000000000..8f8b20bfaeb --- /dev/null +++ b/src/test/debuginfo/type-names.cdb.js @@ -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"); +} diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index cc4a4476d16..934ee2b5d6d 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -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 -// gdbr-check:type = type_names::GenericStruct +// gdb-check:type = type_names::GenericStruct // gdb-command:whatis generic_struct2 -// gdbg-check:type = struct GenericStruct usize> -// gdbr-check:type = type_names::GenericStruct usize> +// gdb-check:type = type_names::GenericStruct 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 -// gdbr-check:type = type_names::mod1::mod2::Enum3 +// gdb-check:type = type_names::mod1::mod2::Enum3 // gdb-command:whatis generic_enum_2 -// gdbg-check:type = union Enum3 -// gdbr-check:type = type_names::mod1::mod2::Enum3 +// 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) -// gdbr-check:type = (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) +// gdb-check:type = (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) // 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, i32) -// gdbr-check:type = (alloc::boxed::Box, i32) +// gdb-check:type = (alloc::boxed::Box, i32) // gdb-command:whatis box2 -// gdbg-check:type = struct (alloc::boxed::Box>, i32) -// gdbr-check:type = (alloc::boxed::Box>, i32) +// gdb-check:type = (alloc::boxed::Box, 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, i32) -// gdbr-check:type = (&type_names::GenericStruct, i32) +// gdb-check:type = (&type_names::GenericStruct, 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, i32) -// gdbr-check:type = (&mut type_names::GenericStruct, i32) +// gdb-check:type = (&mut type_names::GenericStruct, 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, isize) -// gdbr-check:type = (*mut type_names::mod1::mod2::Enum3, isize) +// gdb-check:type = (*mut type_names::mod1::mod2::Enum3, 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, isize) -// gdbr-check:type = (*const type_names::mod1::mod2::Enum3, isize) +// gdb-check:type = (*const type_names::mod1::mod2::Enum3, 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 -// gdbr-check:type = type_names::Box +// gdb-check:type = alloc::boxed::Box // 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> -// gdbr-check:type = type_names::Box> +// gdb-check:type = alloc::boxed::Box, alloc::alloc::Global> // gdb-command:whatis generic_ref_trait -// gdbg-check:type = struct &Trait2 -// gdbr-check:type = type_names::&Trait2 +// gdb-check:type = &dyn type_names::Trait2 // gdb-command:whatis generic_mut_ref_trait -// gdbg-check:type = struct &mut Trait2> -// gdbr-check:type = type_names::&mut Trait2> +// gdb-check:type = &mut dyn type_names::Trait2> + +// gdb-command:whatis no_principal_trait +// gdb-check:type = alloc::boxed::Box // BARE FUNCTIONS // gdb-command:whatis rust_fn -// gdbg-check:type = struct (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) -// gdbr-check:type = (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) +// gdb-check:type = (fn(core::option::Option, 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), usize) -// gdbr-check:type = (unsafe fn(core::result::Result), 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), 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) -> type_names::mod1::Struct2, usize) -// gdbr-check:type = (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) - -// gdb-command:whatis extern_stdcall_fn_with_return_value -// gdbg-check:type = struct (extern "stdcall" fn(alloc::boxed::Box) -> usize, usize) -// gdbr-check:type = (extern "stdcall" fn(alloc::boxed::Box) -> usize, usize) +// gdb-check:type = (unsafe fn(type_names::GenericStruct) -> 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, f64> mut_generic_struct = [...] + +// ENUMS +// cdb-command:dv /t *_enum_* +// cdb-check:union enum$ simple_enum_1 = [...] +// cdb-check:union enum$ 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$ > > tuple1 = [...] +// cdb-check:struct tuple$, enum$, char> tuple2 = [...] + +// BOX +// cdb-command:dv /t box* +// cdb-check:struct tuple$, i32> box1 = [...] +// cdb-check:struct tuple$ >, alloc::alloc::Global>, i32> box2 = [...] + +// REFERENCES +// cdb-command:dv /t *ref* +// cdb-check:struct tuple$, i32> ref1 = [...] +// cdb-check:struct tuple$ >, i32> ref2 = [...] +// cdb-check:struct tuple$, i32> mut_ref1 = [...] +// cdb-check:struct tuple$, f64> >, i32> mut_ref2 = [...] + +// RAW POINTERS +// cdb-command:dv /t *_ptr* +// cdb-check:struct tuple$, isize> mut_ptr1 = [...] +// cdb-check:struct tuple$, isize> mut_ptr2 = [...] +// cdb-check:struct tuple$ > >, isize> mut_ptr3 = [...] +// cdb-check:struct tuple$, isize> const_ptr1 = [...] +// cdb-check:struct tuple$, isize> const_ptr2 = [...] +// cdb-check:struct tuple$ > >, isize> const_ptr3 = [...] + +// VECTORS +// cdb-command:dv /t *vec* +// cdb-check:struct tuple$, i16> fixed_size_vec1 = [...] +// cdb-check:struct tuple$, i16> fixed_size_vec2 = [...] +// cdb-check:struct alloc::vec::Vec vec1 = [...] +// cdb-check:struct alloc::vec::Vec, alloc::alloc::Global> vec2 = [...] +// cdb-command:dv /t slice* +// cdb-check:struct slice$ slice1 = [...] +// cdb-check:struct slice$ > slice2 = [...] + +// TRAITS +// cdb-command:dv /t *_trait +// cdb-check:struct ref_mut$ > > > generic_mut_ref_trait = [...] +// cdb-check:struct ref$ > > generic_ref_trait = [...] +// cdb-check:struct alloc::boxed::Box >, alloc::alloc::Global> generic_box_trait = [...] +// cdb-check:struct alloc::boxed::Box, alloc::alloc::Global> box_trait = [...] +// cdb-check:struct ref$ > ref_trait = [...] +// cdb-check:struct ref_mut$ > mut_ref_trait = [...] +// cdb-check:struct alloc::boxed::Box, alloc::alloc::Global> no_principal_trait = [...] +// cdb-check:struct ref$ > has_associated_type_trait = struct ref$ > + +// BARE FUNCTIONS +// cdb-command:dv /t *_fn* +// cdb-check:struct tuple$), usize> unsafe_fn_with_return_value = [...] +// cdb-check:struct tuple$ extern_c_fn_with_return_value = [...] +// cdb-check:struct tuple$ rust_fn_with_return_value = [...] +// cdb-check:struct tuple$ >), usize> unsafe_fn = [...] +// cdb-check:struct tuple$ extern_c_fn = [...] +// cdb-check:struct tuple$ >, enum$ >, 1, [...], Some>), usize> rust_fn = [...] +// cdb-command:dv /t *_function* +// cdb-check:struct tuple$, ...), usize> variadic_function = [...] +// cdb-check:struct tuple$ generic_function_struct3 = [...] +// cdb-check:struct tuple$ 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$ >,enum$ >, 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$ closure2 = [...] +// cdb-check:struct tuple$ 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 { fn dummy(&self, _: T1, _: T2) {} } +trait Trait3 { + type AssocType; + fn dummy(&self) {} +} impl Trait1 for isize {} impl Trait2 for isize {} +impl Trait3 for isize { + type AssocType = isize; +} fn rust_fn(_: Option, _: Option<&mod1::Struct2>) {} extern "C" fn extern_c_fn(_: isize) {} unsafe fn unsafe_fn(_: Result) {} -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) -> mod1::Struct2 { mod1::Struct2 } -extern "stdcall" fn extern_stdcall_fn_with_return_value(_: Box) -> usize { - 0 -} fn generic_function(x: T) -> T { x @@ -333,28 +400,28 @@ fn main() { let slice2 = &*vec2; // Trait Objects - let box_trait = (box 0_isize) as Box; - let ref_trait = &0_isize as &Trait1; + let box_trait = (box 0_isize) as Box; + 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; + let has_associated_type_trait = &0_isize as &dyn Trait3; - let generic_box_trait = (box 0_isize) as Box>; - let generic_ref_trait = (&0_isize) as &Trait2; + let generic_box_trait = (box 0_isize) as Box>; + let generic_ref_trait = (&0_isize) as &dyn Trait2; let mut generic_mut_ref_trait_impl = 0_isize; let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) - as &mut Trait2>; + as &mut dyn Trait2>; // 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::, 0_usize); let generic_function_struct3 = (generic_function::, 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 } diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index 695cdc4f41f..a2778fc6090 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -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 diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 6a1faee1d8e..49731b2d7dc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -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) } diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 3d5f39e8c90..15ed2f7a0a9 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -52,6 +52,7 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[ "// error-pattern", "// gdb", "// lldb", + "// cdb", "// normalize-stderr-test", ];