about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDaniel Paoliello <danpao@microsoft.com>2021-06-24 10:36:28 -0700
committerDaniel Paoliello <danpao@microsoft.com>2021-06-30 11:10:29 -0700
commitaac8a885520854e4b60ea5733b8b06f9e0cc1fcc (patch)
tree197ee4eeb5aab523079e095ab2f8dd02ba906fa4 /src
parent868c702d0c9a471a28fb55f0148eb1e3e8b1dcc5 (diff)
downloadrust-aac8a885520854e4b60ea5733b8b06f9e0cc1fcc.tar.gz
rust-aac8a885520854e4b60ea5733b8b06f9e0cc1fcc.zip
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).
Diffstat (limited to 'src')
-rw-r--r--src/etc/natvis/intrinsic.natvis26
-rw-r--r--src/etc/natvis/libstd.natvis2
-rw-r--r--src/test/codegen/async-fn-debug-msvc.rs2
-rw-r--r--src/test/codegen/async-fn-debug.rs2
-rw-r--r--src/test/codegen/fn-impl-trait-self.rs3
-rw-r--r--src/test/codegen/generator-debug-msvc.rs2
-rw-r--r--src/test/codegen/generator-debug.rs2
-rw-r--r--src/test/debuginfo/basic-types.rs44
-rw-r--r--src/test/debuginfo/function-names.rs175
-rw-r--r--src/test/debuginfo/generator-objects.rs16
-rw-r--r--src/test/debuginfo/generic-struct.rs21
-rw-r--r--src/test/debuginfo/issue-57822.rs8
-rw-r--r--src/test/debuginfo/msvc-pretty-enums.rs37
-rw-r--r--src/test/debuginfo/mutex.rs3
-rw-r--r--src/test/debuginfo/pretty-std.rs10
-rw-r--r--src/test/debuginfo/rc_arc.rs3
-rw-r--r--src/test/debuginfo/result-types.rs4
-rw-r--r--src/test/debuginfo/simple-tuple.rs14
-rw-r--r--src/test/debuginfo/thread.rs4
-rw-r--r--src/test/debuginfo/tuple-in-tuple.rs42
-rw-r--r--src/test/debuginfo/type-names.cdb.js17
-rw-r--r--src/test/debuginfo/type-names.rs289
-rw-r--r--src/test/debuginfo/var-captured-in-nested-closure.rs2
-rw-r--r--src/tools/compiletest/src/runtest.rs26
-rw-r--r--src/tools/tidy/src/style.rs1
25 files changed, 544 insertions, 211 deletions
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 @@
       </Synthetic>
     </Expand>
   </Type>
-  <Type Name="slice&lt;*&gt;">
+  <Type Name="slice$&lt;*&gt;">
     <DisplayString>{{ len={length} }}</DisplayString>
     <Expand>
       <Item Name="[len]" ExcludeView="simple">length</Item>
@@ -25,23 +25,23 @@
       </ArrayItems>
     </Expand>
   </Type>
-  <Type Name="tuple&lt;&gt;">
+  <Type Name="tuple$&lt;&gt;">
     <DisplayString>()</DisplayString>
   </Type>
-  <Type Name="tuple&lt;*&gt;">
+  <Type Name="tuple$&lt;*&gt;">
     <DisplayString>({__0})</DisplayString>
     <Expand>
       <Item Name="[0]">__0</Item>
     </Expand>
   </Type>
-  <Type Name="tuple&lt;*,*&gt;">
+  <Type Name="tuple$&lt;*,*&gt;">
     <DisplayString>({__0}, {__1})</DisplayString>
     <Expand>
       <Item Name="[0]">__0</Item>
       <Item Name="[1]">__1</Item>
     </Expand>
   </Type>
-  <Type Name="tuple&lt;*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*&gt;">
     <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&lt;*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*&gt;">
     <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&lt;*,*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*,*&gt;">
     <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&lt;*,*,*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*,*,*&gt;">
     <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&lt;*,*,*,*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*,*,*,*&gt;">
     <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&lt;*,*,*,*,*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*,*,*,*,*&gt;">
     <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&lt;*,*,*,*,*,*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*,*,*,*,*,*&gt;">
     <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&lt;*,*,*,*,*,*,*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*,*,*,*,*,*,*&gt;">
     <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&lt;*,*,*,*,*,*,*,*,*,*,*&gt;">
+  <Type Name="tuple$&lt;*,*,*,*,*,*,*,*,*,*,*&gt;">
     <DisplayString>({__0}, {__1}, {__2}, {__3}, {__4}, {__5}, {__6}, {__7}, {__8}, {__9}, ...)</DisplayString>
     <Expand>
       <Item Name="[0]">__0</Item>
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 @@
           <If Condition="(base.table.table.ctrl.pointer[i] &amp; 0x80) == 0">
             <!-- Bucket is populated -->
             <Exec>n--</Exec>
-            <Item Name="{((tuple&lt;$T1, $T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple&lt;$T1, $T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
+            <Item Name="{((tuple$&lt;$T1, $T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple$&lt;$T1, $T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
           </If>
           <Exec>i++</Exec>
         </Loop>
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() -> <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)
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<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,
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<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]*]]
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<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
+}
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<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]
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$<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$]
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$<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>]
 
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<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;
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<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>]
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$<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()
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<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: [...]]
 
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<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 *]
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<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: [...]]
 
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<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
 }
 
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",
 ];