about summary refs log tree commit diff
path: root/tests/codegen-llvm/sanitizer/cfi
diff options
context:
space:
mode:
Diffstat (limited to 'tests/codegen-llvm/sanitizer/cfi')
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs10
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs10
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs10
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs19
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs18
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs19
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs73
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs32
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs45
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs29
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs21
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs86
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs54
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs190
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs79
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs36
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs175
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs62
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs31
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs145
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs24
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs46
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs46
27 files changed, 1384 insertions, 0 deletions
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs
new file mode 100644
index 00000000000..22577e2a3c4
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs
@@ -0,0 +1,10 @@
+// Verifies that "CFI Canonical Jump Tables" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"CFI Canonical Jump Tables", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
new file mode 100644
index 00000000000..a54a6d84a80
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
@@ -0,0 +1,10 @@
+// Verifies that "cfi-normalize-integers" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs
new file mode 100644
index 00000000000..283b8f26102
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs
@@ -0,0 +1,10 @@
+// Verifies that "EnableSplitLTOUnit" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"EnableSplitLTOUnit", i32 1}
diff --git a/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs
new file mode 100644
index 00000000000..df65960dfe0
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs
@@ -0,0 +1,19 @@
+// Verifies that the parent block's debug information are assigned to the inserted cfi block.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!dbg !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK:       [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}"), !dbg !{{[0-9]+}}
+    // CHECK-NEXT:  br i1 [[TT]], label %type_test.pass, label %type_test.fail, !dbg !{{[0-9]+}}
+    // CHECK:       type_test.pass:                                   ; preds = %start
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg), !dbg !{{[0-9]+}}
+    // CHECK:       type_test.fail:                                   ; preds = %start
+    // CHECK-NEXT:  call void @llvm.trap(), !dbg !{{[0-9]+}}
+    // CHECK-NEXT:  unreachable, !dbg !{{[0-9]+}}
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
new file mode 100644
index 00000000000..71ccdc8ca62
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
@@ -0,0 +1,18 @@
+// Verifies that pointer type membership tests for indirect calls are omitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+
+#[no_sanitize(cfi)]
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: emit_type_checks_attr_no_sanitize::foo
+    // CHECK:       Function Attrs: {{.*}}
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg)
+    // CHECK-NEXT:  ret i32 {{%.+}}
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs
new file mode 100644
index 00000000000..ebc66a015df
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs
@@ -0,0 +1,19 @@
+// Verifies that pointer type membership tests for indirect calls are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK:       [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}")
+    // CHECK-NEXT:  br i1 [[TT]], label %type_test.pass, label %type_test.fail
+    // CHECK:       type_test.pass:
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg)
+    // CHECK:       type_test.fail:
+    // CHECK-NEXT:  call void @llvm.trap()
+    // CHECK-NEXT:  unreachable
+    f(arg)
+}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs
new file mode 100644
index 00000000000..9bc2e42db0f
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs
@@ -0,0 +1,73 @@
+// Verifies that user-defined CFI encoding for types are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(cfi_encoding, extern_types)]
+
+#[cfi_encoding = "3Foo"]
+pub struct Type1(i32);
+
+extern "C" {
+    #[cfi_encoding = "3Bar"]
+    type Type2;
+}
+
+#[cfi_encoding = "3Baz"]
+#[repr(transparent)]
+pub struct Type3(i32);
+
+#[cfi_encoding = "i"]
+pub struct Type4(i32);
+
+#[cfi_encoding = "j"]
+#[repr(transparent)]
+pub struct Type5(u32);
+
+pub fn foo0(_: Type1) {}
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo1(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: *mut Type2) {}
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: *mut Type2, _: *mut Type2) {}
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: *mut Type2, _: *mut Type2, _: *mut Type2) {}
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: *mut Type3) {}
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *mut Type3, _: *mut Type3) {}
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *mut Type3, _: *mut Type3, _: *mut Type3) {}
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: Type4) {}
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: Type4, _: Type4) {}
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: Type4, _: Type4, _: Type4) {}
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: Type5) {}
+// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: Type5, _: Type5) {}
+// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: Type5, _: Type5, _: Type5) {}
+// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFv3FooE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFv3FooS_E"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFv3FooS_S_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvP3BarE"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvP3BarS0_E"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvP3BarS0_S0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvP3BazE"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvP3BazS0_E"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvP3BazS0_S0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFviE"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFviiE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFviiiE"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvjE"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvjjE"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvjjjE"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs
new file mode 100644
index 00000000000..9048c6a1f18
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs
@@ -0,0 +1,32 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for const generics.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(type_alias_impl_trait)]
+
+extern crate core;
+
+pub type Type1 = impl Send;
+
+#[define_opaque(Type1)]
+pub fn foo()
+where
+    Type1: 'static,
+{
+    pub struct Foo<T, const N: usize>([T; N]);
+    let _: Type1 = Foo([0; 32]);
+}
+
+pub fn foo1(_: Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooIu3i32Lu5usize32EES2_S2_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
new file mode 100644
index 00000000000..8fec275fd06
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
@@ -0,0 +1,31 @@
+// Verifies that type metadata identifiers for drop functions are emitted correctly.
+//
+// Non needs_drop drop glue isn't codegen'd at all, so we don't try to check the IDs there. But we
+// do check it's not emitted which should help catch bugs if we do start generating it again in the
+// future.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$
+// CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+// CHECK:       call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE")
+
+struct EmptyDrop;
+// CHECK-NOT: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+struct PresentDrop;
+
+impl Drop for PresentDrop {
+    fn drop(&mut self) {}
+    // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}PresentDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+}
+
+pub fn foo() {
+    let _ = Box::new(EmptyDrop) as Box<dyn Send>;
+    let _ = Box::new(PresentDrop) as Box<dyn Send>;
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs
new file mode 100644
index 00000000000..7e60aafff68
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs
@@ -0,0 +1,45 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for function types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+pub fn foo1(_: fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &dyn Fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &dyn FnMut(i32) -> i32) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs
new file mode 100644
index 00000000000..36d2e8c9f25
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs
@@ -0,0 +1,29 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for lifetimes/regions.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(type_alias_impl_trait)]
+
+extern crate core;
+
+pub type Type1 = impl Send;
+
+#[define_opaque(Type1)]
+pub fn foo<'a>()
+where
+    Type1: 'static,
+{
+    pub struct Foo<'a>(&'a i32);
+    pub struct Bar<'a, 'b>(&'a i32, &'b Foo<'b>);
+    let _: Type1 = Bar;
+}
+
+pub fn foo1(_: Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
new file mode 100644
index 00000000000..9d611777ff0
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
@@ -0,0 +1,21 @@
+// Verifies that a secondary type metadata identifier is assigned to methods with their concrete
+// self so they can be used as function pointers.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+trait Trait1 {
+    fn foo(&self);
+}
+
+struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+    // CHECK: define{{.*}}3foo{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
new file mode 100644
index 00000000000..a8ba8db1be3
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
@@ -0,0 +1,86 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for paths.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+#![feature(type_alias_impl_trait)]
+
+extern crate core;
+
+pub type Type1 = impl Send;
+pub type Type2 = impl Send;
+pub type Type3 = impl Send;
+pub type Type4 = impl Send;
+
+#[define_opaque(Type1, Type2, Type4)]
+pub fn foo() {
+    // Type in extern path
+    extern "C" {
+        fn bar();
+    }
+    let _: Type1 = bar;
+
+    // Type in closure path
+    || {
+        pub struct Foo;
+        let _: Type2 = Foo;
+    };
+
+    // Type in const path
+    const {
+        pub struct Foo;
+        #[define_opaque(Type3)]
+        fn bar() -> Type3 {
+            Foo
+        }
+    };
+
+    // Type in impl path
+    struct Foo;
+    impl Foo {
+        fn bar(&self) {}
+    }
+    let _: Type4 = <Foo>::bar;
+}
+
+// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore
+
+pub fn foo1(_: &Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &Type1, _: &Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &Type1, _: &Type1, _: &Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &Type2) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &Type2, _: &Type2) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &Type2, _: &Type2, _: &Type2) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &Type3) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &Type3, _: &Type3) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &Type3, _: &Type3, _: &Type3) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: &Type4) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: &Type4, _: &Type4) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs
new file mode 100644
index 00000000000..d37bb740f55
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs
@@ -0,0 +1,54 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for pointer types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+pub fn foo1(_: &mut i32) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &mut i32, _: &i32) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &mut i32, _: &i32, _: &i32) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &i32) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &i32, _: &mut i32) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &i32, _: &mut i32, _: &mut i32) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *mut i32) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *mut i32, _: *const i32) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: *mut i32, _: *const i32, _: *const i32) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: *const i32) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: *const i32, _: *mut i32) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: *const i32, _: *mut i32, _: *mut i32) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: fn(i32) -> i32) {}
+// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo15(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) {}
+// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPu3i32E"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKu3i32E"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
new file mode 100644
index 00000000000..7d9e4d05872
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
@@ -0,0 +1,190 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for primitive types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+extern crate core;
+use core::ffi::*;
+
+pub fn foo1(_: ()) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: (), _: c_void) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: (), _: c_void, _: c_void) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: *mut ()) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: *mut (), _: *mut c_void) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: *mut (), _: *mut c_void, _: *mut c_void) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *const ()) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *const (), _: *const c_void) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: *const (), _: *const c_void, _: *const c_void) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: bool) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: bool, _: bool) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: bool, _: bool, _: bool) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: i8) {}
+// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: i8, _: i8) {}
+// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo15(_: i8, _: i8, _: i8) {}
+// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo16(_: i16) {}
+// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo17(_: i16, _: i16) {}
+// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo18(_: i16, _: i16, _: i16) {}
+// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo19(_: i32) {}
+// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo20(_: i32, _: i32) {}
+// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo21(_: i32, _: i32, _: i32) {}
+// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo22(_: i64) {}
+// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo23(_: i64, _: i64) {}
+// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo24(_: i64, _: i64, _: i64) {}
+// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo25(_: i128) {}
+// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo26(_: i128, _: i128) {}
+// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo27(_: i128, _: i128, _: i128) {}
+// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo28(_: isize) {}
+// CHECK: define{{.*}}5foo28{{.*}}!type ![[TYPE28:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo29(_: isize, _: isize) {}
+// CHECK: define{{.*}}5foo29{{.*}}!type ![[TYPE29:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo30(_: isize, _: isize, _: isize) {}
+// CHECK: define{{.*}}5foo30{{.*}}!type ![[TYPE30:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo31(_: u8) {}
+// CHECK: define{{.*}}5foo31{{.*}}!type ![[TYPE31:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo32(_: u8, _: u8) {}
+// CHECK: define{{.*}}5foo32{{.*}}!type ![[TYPE32:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo33(_: u8, _: u8, _: u8) {}
+// CHECK: define{{.*}}5foo33{{.*}}!type ![[TYPE33:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo34(_: u16) {}
+// CHECK: define{{.*}}5foo34{{.*}}!type ![[TYPE34:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo35(_: u16, _: u16) {}
+// CHECK: define{{.*}}5foo35{{.*}}!type ![[TYPE35:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo36(_: u16, _: u16, _: u16) {}
+// CHECK: define{{.*}}5foo36{{.*}}!type ![[TYPE36:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo37(_: u32) {}
+// CHECK: define{{.*}}5foo37{{.*}}!type ![[TYPE37:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo38(_: u32, _: u32) {}
+// CHECK: define{{.*}}5foo38{{.*}}!type ![[TYPE38:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo39(_: u32, _: u32, _: u32) {}
+// CHECK: define{{.*}}5foo39{{.*}}!type ![[TYPE39:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo40(_: u64) {}
+// CHECK: define{{.*}}5foo40{{.*}}!type ![[TYPE40:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo41(_: u64, _: u64) {}
+// CHECK: define{{.*}}5foo41{{.*}}!type ![[TYPE41:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo42(_: u64, _: u64, _: u64) {}
+// CHECK: define{{.*}}5foo42{{.*}}!type ![[TYPE42:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo43(_: u128) {}
+// CHECK: define{{.*}}5foo43{{.*}}!type ![[TYPE43:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo44(_: u128, _: u128) {}
+// CHECK: define{{.*}}5foo44{{.*}}!type ![[TYPE44:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo45(_: u128, _: u128, _: u128) {}
+// CHECK: define{{.*}}5foo45{{.*}}!type ![[TYPE45:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo46(_: usize) {}
+// CHECK: define{{.*}}5foo46{{.*}}!type ![[TYPE46:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo47(_: usize, _: usize) {}
+// CHECK: define{{.*}}5foo47{{.*}}!type ![[TYPE47:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo48(_: usize, _: usize, _: usize) {}
+// CHECK: define{{.*}}5foo48{{.*}}!type ![[TYPE48:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo49(_: f32) {}
+// CHECK: define{{.*}}5foo49{{.*}}!type ![[TYPE49:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo50(_: f32, _: f32) {}
+// CHECK: define{{.*}}5foo50{{.*}}!type ![[TYPE50:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo51(_: f32, _: f32, _: f32) {}
+// CHECK: define{{.*}}5foo51{{.*}}!type ![[TYPE51:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo52(_: f64) {}
+// CHECK: define{{.*}}5foo52{{.*}}!type ![[TYPE52:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo53(_: f64, _: f64) {}
+// CHECK: define{{.*}}5foo53{{.*}}!type ![[TYPE53:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo54(_: f64, _: f64, _: f64) {}
+// CHECK: define{{.*}}5foo54{{.*}}!type ![[TYPE54:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo55(_: char) {}
+// CHECK: define{{.*}}5foo55{{.*}}!type ![[TYPE55:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo56(_: char, _: char) {}
+// CHECK: define{{.*}}5foo56{{.*}}!type ![[TYPE56:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo57(_: char, _: char, _: char) {}
+// CHECK: define{{.*}}5foo57{{.*}}!type ![[TYPE57:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo58(_: &str) {}
+// CHECK: define{{.*}}5foo58{{.*}}!type ![[TYPE58:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo59(_: &str, _: &str) {}
+// CHECK: define{{.*}}5foo59{{.*}}!type ![[TYPE59:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo60(_: &str, _: &str, _: &str) {}
+// CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvS_S_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbE"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvbbbE"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8E"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu2i8S_S_E"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16E"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_E"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i16S_S_E"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32E"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_E"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i32S_S_E"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64E"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_E"}
+// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3i64S_S_E"}
+// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128E"}
+// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_E"}
+// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu4i128S_S_E"}
+// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeE"}
+// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_E"}
+// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"}
+// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8E"}
+// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_E"}
+// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu2u8S_S_E"}
+// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16E"}
+// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_E"}
+// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u16S_S_E"}
+// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32E"}
+// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_E"}
+// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u32S_S_E"}
+// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64E"}
+// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_E"}
+// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu3u64S_S_E"}
+// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128E"}
+// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_E"}
+// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu4u128S_S_E"}
+// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeE"}
+// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_E"}
+// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"}
+// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvfE"}
+// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvffE"}
+// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvfffE"}
+// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvdE"}
+// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvddE"}
+// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvdddE"}
+// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charE"}
+// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_E"}
+// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu4charS_S_E"}
+// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strEE"}
+// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"}
+// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
new file mode 100644
index 00000000000..0f97c70f3f9
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
@@ -0,0 +1,79 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for repr transparent types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+extern crate core;
+use core::ffi::*;
+use std::marker::PhantomData;
+
+struct Foo(i32);
+
+// repr(transparent) user-defined type
+#[repr(transparent)]
+pub struct Type1 {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: Foo,
+}
+
+// Self-referencing repr(transparent) user-defined type
+#[repr(transparent)]
+pub struct Type2<'a> {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: &'a Type2<'a>,
+}
+
+pub struct Bar(i32);
+
+// repr(transparent) user-defined generic type
+#[repr(transparent)]
+pub struct Type3<T>(T);
+
+// repr(transparent) wrapper which engages in self-reference
+#[repr(transparent)]
+pub struct Type4(Type4Helper<Type4>);
+#[repr(transparent)]
+pub struct Type4Helper<T>(*mut T);
+
+pub fn foo1(_: Type1) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: Type1, _: Type1, _: Type1) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: Type2) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: Type2, _: Type2) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: Type2, _: Type2, _: Type2) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: Type3<Bar>) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: Type3<Bar>, _: Type3<Bar>) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: Type3<Bar>, _: Type3<Bar>, _: Type3<Bar>) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: Type4) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: Type4, _: Type4) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: Type4, _: Type4, _: Type4) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_S_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_S_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4E"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs
new file mode 100644
index 00000000000..bdee3f47a83
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs
@@ -0,0 +1,36 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for sequence types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+pub fn foo1(_: (i32, i32)) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: (i32, i32), _: (i32, i32)) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: (i32, i32), _: (i32, i32), _: (i32, i32)) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: [i32; 32]) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: [i32; 32], _: [i32; 32]) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: [i32; 32], _: [i32; 32], _: [i32; 32]) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &[i32]) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &[i32], _: &[i32]) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &[i32], _: &[i32], _: &[i32]) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvA32u3i32E"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs
new file mode 100644
index 00000000000..55e816178f8
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs
@@ -0,0 +1,175 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for trait types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub trait Trait1 {
+    fn foo(&self);
+}
+
+#[derive(Clone, Copy)]
+pub struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+}
+
+pub trait Trait2<T> {
+    fn bar(&self);
+}
+
+pub struct Type2;
+
+impl Trait2<i32> for Type2 {
+    fn bar(&self) {}
+}
+
+pub trait Trait3<T> {
+    fn baz(&self, _: &T);
+}
+
+pub struct Type3;
+
+impl<T, U> Trait3<U> for T {
+    fn baz(&self, _: &U) {}
+}
+
+pub trait Trait4<'a, T> {
+    type Output: 'a;
+    fn qux(&self, _: &T) -> Self::Output;
+}
+
+pub struct Type4;
+
+impl<'a, T, U> Trait4<'a, U> for T {
+    type Output = &'a i32;
+    fn qux(&self, _: &U) -> Self::Output {
+        &0
+    }
+}
+
+pub trait Trait5<T, const N: usize> {
+    fn quux(&self, _: &[T; N]);
+}
+
+#[derive(Copy, Clone)]
+pub struct Type5;
+
+impl<T, U, const N: usize> Trait5<U, N> for T {
+    fn quux(&self, _: &[U; N]) {}
+}
+
+pub fn foo1(_: &dyn Send) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &dyn Send, _: &dyn Send) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &dyn Send, _: &dyn Send, _: &dyn Send) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &(dyn Send + Sync)) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &(dyn Send + Sync), _: &(dyn Sync + Send)) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &(dyn Send + Sync), _: &(dyn Sync + Send), _: &(dyn Sync + Send)) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &(dyn Trait1 + Send)) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send), _: &(dyn Trait1 + Send)) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: &(dyn Trait1 + Send + Sync)) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: &(dyn Trait1 + Send + Sync), _: &(dyn Trait1 + Sync + Send)) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(
+    _: &(dyn Trait1 + Send + Sync),
+    _: &(dyn Trait1 + Sync + Send),
+    _: &(dyn Trait1 + Sync + Send),
+) {
+}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo13(_: &dyn Trait1) {}
+// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo14(_: &dyn Trait1, _: &dyn Trait1) {}
+// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo15(_: &dyn Trait1, _: &dyn Trait1, _: &dyn Trait1) {}
+// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo16<T>(_: &dyn Trait2<T>) {}
+pub fn bar16() {
+    let a = Type2;
+    foo16(&a);
+}
+// CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo17<T>(_: &dyn Trait2<T>, _: &dyn Trait2<T>) {}
+pub fn bar17() {
+    let a = Type2;
+    foo17(&a, &a);
+}
+// CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo18<T>(_: &dyn Trait2<T>, _: &dyn Trait2<T>, _: &dyn Trait2<T>) {}
+pub fn bar18() {
+    let a = Type2;
+    foo18(&a, &a, &a);
+}
+// CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo19(_: &dyn Trait3<Type3>) {}
+// CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo20(_: &dyn Trait3<Type3>, _: &dyn Trait3<Type3>) {}
+// CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo21(_: &dyn Trait3<Type3>, _: &dyn Trait3<Type3>, _: &dyn Trait3<Type3>) {}
+// CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo22<'a>(_: &dyn Trait4<'a, Type4, Output = &'a i32>) {}
+// CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo23<'a>(
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+) {
+}
+// CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo24<'a>(
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+    _: &dyn Trait4<'a, Type4, Output = &'a i32>,
+) {
+}
+// CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo25(_: &dyn Trait5<Type5, 32>) {}
+// CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo26(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>) {}
+// CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo27(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>) {}
+// CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEEE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"}
+// FIXME(rcvalle): Enforce autotraits ordering when encoding (e.g., alphabetical order)
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_S3_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_S3_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_S4_E"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_S2_E"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_E"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_S3_E"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEEE"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_E"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_S3_E"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EEE"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_E"}
+// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_S6_E"}
+// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEEE"}
+// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_E"}
+// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_S5_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs
new file mode 100644
index 00000000000..c1f3ca61afe
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs
@@ -0,0 +1,62 @@
+// Verifies that type metadata identifiers for functions are emitted correctly
+// for user-defined types.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type = "lib"]
+#![feature(extern_types)]
+
+pub struct Struct1<T> {
+    member1: T,
+}
+
+pub enum Enum1<T> {
+    Variant1(T),
+}
+
+pub union Union1<T> {
+    member1: std::mem::ManuallyDrop<T>,
+}
+
+extern "C" {
+    pub type type1;
+}
+
+pub fn foo1(_: &Struct1<i32>) {}
+// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &Struct1<i32>, _: &Struct1<i32>) {}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &Struct1<i32>, _: &Struct1<i32>, _: &Struct1<i32>) {}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &Enum1<i32>) {}
+// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &Enum1<i32>, _: &Enum1<i32>) {}
+// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: &Enum1<i32>, _: &Enum1<i32>, _: &Enum1<i32>) {}
+// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: &Union1<i32>) {}
+// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: &Union1<i32>, _: &Union1<i32>) {}
+// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: &Union1<i32>, _: &Union1<i32>, _: &Union1<i32>) {}
+// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: *mut type1) {}
+// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: *mut type1, _: *mut type1) {}
+// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo12(_: *mut type1, _: *mut type1, _: *mut type1) {}
+// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}7Struct1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Enum1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Union1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvP5type1E"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvP5type1S0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs
new file mode 100644
index 00000000000..32637b64b3e
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs
@@ -0,0 +1,31 @@
+// Verifies that generalized type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.generalized")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.generalized")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.generalized")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.generalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.generalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.generalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
new file mode 100644
index 00000000000..51121b0aef1
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
@@ -0,0 +1,31 @@
+// Verifies that normalized and generalized type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}![[TYPE1:[0-9]+]]
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized.generalized")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}![[TYPE2:[0-9]+]]
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized.generalized")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}![[TYPE3:[0-9]+]]
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized.generalized")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PKvS_E.normalized.generalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PKvS_S_E.normalized.generalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PKvS_S_S_E.normalized.generalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs
new file mode 100644
index 00000000000..1cfdd23006e
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs
@@ -0,0 +1,31 @@
+// Verifies that normalized type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E.normalized")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E.normalized")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E.normalized")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E.normalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E.normalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E.normalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs
new file mode 100644
index 00000000000..56ab1ce4b35
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs
@@ -0,0 +1,31 @@
+// Verifies that type metadata for functions are emitted.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME:  {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_E")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME:  {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_E")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME:  {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"_ZTSFu3i32S_S_S_E")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs
new file mode 100644
index 00000000000..0e57ce322d1
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs
@@ -0,0 +1,145 @@
+// Verifies that type metadata identifiers for trait objects are emitted correctly.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type = "lib"]
+
+pub trait Trait1 {
+    fn foo(&self);
+}
+
+#[derive(Clone, Copy)]
+pub struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+}
+
+pub trait Trait2<T> {
+    fn bar(&self);
+}
+
+pub struct Type2;
+
+impl Trait2<i32> for Type2 {
+    fn bar(&self) {}
+}
+
+pub trait Trait3<T> {
+    fn baz(&self, _: &T);
+}
+
+pub struct Type3;
+
+impl<T, U> Trait3<U> for T {
+    fn baz(&self, _: &U) {}
+}
+
+pub trait Trait4<'a, T> {
+    type Output: 'a;
+    fn qux(&self, _: &T) -> Self::Output;
+}
+
+pub struct Type4;
+
+impl<'a, T, U> Trait4<'a, U> for T {
+    type Output = &'a i32;
+    fn qux(&self, _: &U) -> Self::Output {
+        &0
+    }
+}
+
+pub trait Trait5<T, const N: usize> {
+    fn quux(&self, _: &[T; N]);
+}
+
+#[derive(Copy, Clone)]
+pub struct Type5;
+
+impl<T, U, const N: usize> Trait5<U, N> for T {
+    fn quux(&self, _: &[U; N]) {}
+}
+
+pub fn foo1(a: &dyn Trait1) {
+    a.foo();
+    // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]")
+}
+
+pub fn bar1() {
+    let a = Type1;
+    let b = &a as &dyn Trait1;
+    b.foo();
+    // CHECK-LABEL: define{{.*}}4bar1{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+}
+
+pub fn foo2<T>(a: &dyn Trait2<T>) {
+    a.bar();
+    // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+}
+
+pub fn bar2() {
+    let a = Type2;
+    foo2(&a);
+    let b = &a as &dyn Trait2<i32>;
+    b.bar();
+    // CHECK-LABEL: define{{.*}}4bar2{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]")
+}
+
+pub fn foo3(a: &dyn Trait3<Type3>) {
+    let b = Type3;
+    a.baz(&b);
+    // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
+}
+
+pub fn bar3() {
+    let a = Type3;
+    foo3(&a);
+    let b = &a as &dyn Trait3<Type3>;
+    b.baz(&a);
+    // CHECK-LABEL: define{{.*}}4bar3{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]")
+}
+
+pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) {
+    let b = Type4;
+    a.qux(&b);
+    // CHECK-LABEL: define{{.*}}4foo4{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
+}
+
+pub fn bar4<'a>() {
+    let a = Type4;
+    foo4(&a);
+    let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>;
+    b.qux(&a);
+    // CHECK-LABEL: define{{.*}}4bar4{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE4:[[:print:]]+]]")
+}
+
+pub fn foo5(a: &dyn Trait5<Type5, 32>) {
+    let b = &[Type5; 32];
+    a.quux(&b);
+    // CHECK-LABEL: define{{.*}}4foo5{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
+}
+
+pub fn bar5() {
+    let a = &[Type5; 32];
+    foo5(&a);
+    let b = &a as &dyn Trait5<Type5, 32>;
+    b.quux(&a);
+    // CHECK-LABEL: define{{.*}}4bar5{{.*}}!type !{{[0-9]+}}
+    // CHECK:       call i1 @llvm.type.test(ptr {{%f|%[0-9]}}, metadata !"[[TYPE5:[[:print:]]+]]")
+}
+
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE2]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE3]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE4]]"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE5]]"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs
new file mode 100644
index 00000000000..00e9b5029af
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs
@@ -0,0 +1,24 @@
+// Verifies that type metadata identifiers for for weakly-linked symbols are
+// emitted correctly.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+#![crate_type = "bin"]
+#![feature(linkage)]
+
+unsafe extern "C" {
+    #[linkage = "extern_weak"]
+    static FOO: Option<unsafe extern "C" fn(f64) -> ()>;
+}
+// CHECK: @_rust_extern_with_linkage_FOO = internal global ptr @FOO
+
+fn main() {
+    unsafe {
+        if let Some(method) = FOO {
+            method(4.2);
+            // CHECK: call i1 @llvm.type.test(ptr {{%method|%0}}, metadata !"_ZTSFvdE")
+        }
+    }
+}
+
+// CHECK: declare !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} extern_weak void @FOO(double) unnamed_addr #{{[0-9]+}}
diff --git a/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs
new file mode 100644
index 00000000000..57004da6f8e
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs
@@ -0,0 +1,46 @@
+// Verifies that pointer types are generalized.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0
+
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub fn foo0(_: &mut i32) {}
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo1(_: &mut i32, _: &mut i32) {}
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo2(_: &mut i32, _: &mut i32, _: &mut i32) {}
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo3(_: &i32) {}
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo4(_: &i32, _: &i32) {}
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo5(_: &i32, _: &i32, _: &i32) {}
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo6(_: *mut i32) {}
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo7(_: *mut i32, _: *mut i32) {}
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo8(_: *mut i32, _: *mut i32, _: *mut i32) {}
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo9(_: *const i32) {}
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo10(_: *const i32, _: *const i32) {}
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+pub fn foo11(_: *const i32, _: *const i32, _: *const i32) {}
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvU3mutu3refIvEE.generalized"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_E.generalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvU3mutu3refIvES0_S0_E.generalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIvEE.generalized"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIvES_E.generalized"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIvES_S_E.generalized"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvE.generalized"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPvS_E.generalized"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPvS_S_E.generalized"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvPKvE.generalized"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPKvS0_E.generalized"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPKvS0_S0_E.generalized"}
diff --git a/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs
new file mode 100644
index 00000000000..770ee4e64e0
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs
@@ -0,0 +1,46 @@
+// Verifies that integer types are normalized.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0
+
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub fn foo0(_: bool) {}
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo1(_: bool, _: bool) {}
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo2(_: bool, _: bool, _: bool) {}
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo3(_: char) {}
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo4(_: char, _: char) {}
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo5(_: char, _: char, _: char) {}
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo6(_: isize) {}
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo7(_: isize, _: isize) {}
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo8(_: isize, _: isize, _: isize) {}
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo9(_: (), _: usize) {}
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo10(_: (), _: usize, _: usize) {}
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}}
+pub fn foo11(_: (), _: usize, _: usize, _: usize) {}
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2u8E.normalized"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3u32E.normalized"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3u32S_E.normalized"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3u32S_S_E.normalized"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"}