about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-02 22:59:19 +0000
committerbors <bors@rust-lang.org>2024-03-02 22:59:19 +0000
commit0decdac390cfeedcd7f2f44c45f72c59c70d8143 (patch)
tree373fbe344b85306b4bb3d048b0b9ab1952a25c06
parent5119208fd78a77547c705d1695428c88d6791263 (diff)
parent4c65eef26937b4ea9572eb953ebc523a6cab167b (diff)
downloadrust-0decdac390cfeedcd7f2f44c45f72c59c70d8143.tar.gz
rust-0decdac390cfeedcd7f2f44c45f72c59c70d8143.zip
Auto merge of #121914 - Nadrieril:rollup-ol98ncg, r=Nadrieril
Rollup of 5 pull requests

Successful merges:

 - #120761 (Add initial support for DataFlowSanitizer)
 - #121622 (Preserve same vtable pointer when cloning raw waker, to fix Waker::will_wake)
 - #121716 (match lowering: Lower bindings in a predictable order)
 - #121731 (Now that inlining, mir validation and const eval all use reveal-all, we won't be constraining hidden types here anymore)
 - #121841 (`f16` and `f128` step 2: intrinsics)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast/src/ast.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs48
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs67
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs5
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs25
-rw-r--r--compiler/rustc_hir/src/hir.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs74
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp16
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs70
-rw-r--r--compiler/rustc_session/src/options.rs20
-rw-r--r--compiler/rustc_span/src/symbol.rs46
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs17
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs3
-rw-r--r--compiler/rustc_target/src/spec/mod.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs1
-rw-r--r--library/alloc/src/task.rs13
-rw-r--r--library/alloc/tests/lib.rs2
-rw-r--r--library/alloc/tests/task.rs34
-rwxr-xr-xsrc/bootstrap/configure.py2
-rw-r--r--src/bootstrap/download-ci-llvm-stamp2
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md34
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs4
-rw-r--r--src/tools/compiletest/src/common.rs1
-rw-r--r--src/tools/compiletest/src/header/needs.rs7
-rw-r--r--src/tools/tidy/src/ui_tests.rs1
-rw-r--r--tests/codegen/sanitizer/dataflow-instrument-functions.rs10
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff6
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff6
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff6
-rw-r--r--tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff12
-rw-r--r--tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff48
-rw-r--r--tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff6
-rw-r--r--tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir8
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr (renamed from tests/ui/impl-trait/hidden-type-is-opaque-2.stderr)4
-rw-r--r--tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr31
-rw-r--r--tests/ui/impl-trait/hidden-type-is-opaque-2.rs2
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs17
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.stderr31
-rw-r--r--tests/ui/sanitizer/dataflow-abilist.txt505
-rw-r--r--tests/ui/sanitizer/dataflow.rs60
52 files changed, 1156 insertions, 144 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 18888dd2be5..13b1a589d9b 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1920,22 +1920,28 @@ pub struct FnSig {
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum FloatTy {
+    F16,
     F32,
     F64,
+    F128,
 }
 
 impl FloatTy {
     pub fn name_str(self) -> &'static str {
         match self {
+            FloatTy::F16 => "f16",
             FloatTy::F32 => "f32",
             FloatTy::F64 => "f64",
+            FloatTy::F128 => "f128",
         }
     }
 
     pub fn name(self) -> Symbol {
         match self {
+            FloatTy::F16 => sym::f16,
             FloatTy::F32 => sym::f32,
             FloatTy::F64 => sym::f64,
+            FloatTy::F128 => sym::f128,
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 08aab849868..031bbd63361 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -519,12 +519,22 @@ pub(crate) unsafe fn llvm_optimize(
     let pgo_sample_use_path = get_pgo_sample_use_path(config);
     let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
     let instr_profile_output_path = get_instr_profile_output_path(config);
+    let sanitize_dataflow_abilist: Vec<_> = config
+        .sanitizer_dataflow_abilist
+        .iter()
+        .map(|file| CString::new(file.as_str()).unwrap())
+        .collect();
+    let sanitize_dataflow_abilist_ptrs: Vec<_> =
+        sanitize_dataflow_abilist.iter().map(|file| file.as_ptr()).collect();
     // Sanitizer instrumentation is only inserted during the pre-link optimization stage.
     let sanitizer_options = if !is_lto {
         Some(llvm::SanitizerOptions {
             sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
             sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
             sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI),
+            sanitize_dataflow: config.sanitizer.contains(SanitizerSet::DATAFLOW),
+            sanitize_dataflow_abilist: sanitize_dataflow_abilist_ptrs.as_ptr(),
+            sanitize_dataflow_abilist_len: sanitize_dataflow_abilist_ptrs.len(),
             sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI),
             sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
             sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 7dfcf1ab50e..16122e5557e 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -685,8 +685,10 @@ impl<'ll> CodegenCx<'ll, '_> {
         let t_i64 = self.type_i64();
         let t_i128 = self.type_i128();
         let t_isize = self.type_isize();
+        let t_f16 = self.type_f16();
         let t_f32 = self.type_f32();
         let t_f64 = self.type_f64();
+        let t_f128 = self.type_f128();
         let t_metadata = self.type_metadata();
         let t_token = self.type_token();
 
@@ -728,69 +730,115 @@ impl<'ll> CodegenCx<'ll, '_> {
         ifn!("llvm.debugtrap", fn() -> void);
         ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
 
+        ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16);
         ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
         ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
+        ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128);
 
+        ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16);
         ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64);
+        ifn!("llvm.pow.f128", fn(t_f128, t_f128) -> t_f128);
 
+        ifn!("llvm.sqrt.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.sqrt.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.sin.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.sin.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.sin.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.sin.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.cos.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.cos.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.cos.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.cos.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.exp.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.exp.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.exp.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.exp.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.exp2.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.exp2.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.log.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.log.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.log.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.log.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.log10.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.log10.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.log10.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.log10.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.log2.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.log2.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.log2.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.log2.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.fma.f16", fn(t_f16, t_f16, t_f16) -> t_f16);
         ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
         ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
+        ifn!("llvm.fma.f128", fn(t_f128, t_f128, t_f128) -> t_f128);
 
+        ifn!("llvm.fabs.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.fabs.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.minnum.f16", fn(t_f16, t_f16) -> t_f16);
         ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
+        ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128);
+
+        ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16);
         ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
+        ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128);
 
+        ifn!("llvm.floor.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.floor.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.ceil.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.ceil.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.trunc.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.trunc.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.copysign.f16", fn(t_f16, t_f16) -> t_f16);
         ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64);
+        ifn!("llvm.copysign.f128", fn(t_f128, t_f128) -> t_f128);
 
+        ifn!("llvm.round.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.round.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.round.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.round.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.roundeven.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.roundeven.f128", fn(t_f128) -> t_f128);
 
+        ifn!("llvm.rint.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.rint.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.rint.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.rint.f128", fn(t_f128) -> t_f128);
+
+        ifn!("llvm.nearbyint.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64);
+        ifn!("llvm.nearbyint.f128", fn(t_f128) -> t_f128);
 
         ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8);
         ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 045b6d2b651..1a5f9b42947 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -695,7 +695,7 @@ impl MsvcBasicName for ty::UintTy {
 
 impl MsvcBasicName for ty::FloatTy {
     fn msvc_basic_name(self) -> &'static str {
-        // FIXME: f16 and f128 have no MSVE representation. We could improve the debuginfo.
+        // FIXME: f16 and f128 have no MSVC representation. We could improve the debuginfo.
         // See: <https://github.com/rust-lang/rust/pull/114607/files#r1454683264>
         match self {
             ty::FloatTy::F16 => "half",
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 1d4ab866cb3..f33a672aff0 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -28,51 +28,118 @@ fn get_simple_intrinsic<'ll>(
     name: Symbol,
 ) -> Option<(&'ll Type, &'ll Value)> {
     let llvm_name = match name {
+        sym::sqrtf16 => "llvm.sqrt.f16",
         sym::sqrtf32 => "llvm.sqrt.f32",
         sym::sqrtf64 => "llvm.sqrt.f64",
+        sym::sqrtf128 => "llvm.sqrt.f128",
+
+        sym::powif16 => "llvm.powi.f16",
         sym::powif32 => "llvm.powi.f32",
         sym::powif64 => "llvm.powi.f64",
+        sym::powif128 => "llvm.powi.f128",
+
+        sym::sinf16 => "llvm.sin.f16",
         sym::sinf32 => "llvm.sin.f32",
         sym::sinf64 => "llvm.sin.f64",
+        sym::sinf128 => "llvm.sin.f128",
+
+        sym::cosf16 => "llvm.cos.f16",
         sym::cosf32 => "llvm.cos.f32",
         sym::cosf64 => "llvm.cos.f64",
+        sym::cosf128 => "llvm.cos.f128",
+
+        sym::powf16 => "llvm.pow.f16",
         sym::powf32 => "llvm.pow.f32",
         sym::powf64 => "llvm.pow.f64",
+        sym::powf128 => "llvm.pow.f128",
+
+        sym::expf16 => "llvm.exp.f16",
         sym::expf32 => "llvm.exp.f32",
         sym::expf64 => "llvm.exp.f64",
+        sym::expf128 => "llvm.exp.f128",
+
+        sym::exp2f16 => "llvm.exp2.f16",
         sym::exp2f32 => "llvm.exp2.f32",
         sym::exp2f64 => "llvm.exp2.f64",
+        sym::exp2f128 => "llvm.exp2.f128",
+
+        sym::logf16 => "llvm.log.f16",
         sym::logf32 => "llvm.log.f32",
         sym::logf64 => "llvm.log.f64",
+        sym::logf128 => "llvm.log.f128",
+
+        sym::log10f16 => "llvm.log10.f16",
         sym::log10f32 => "llvm.log10.f32",
         sym::log10f64 => "llvm.log10.f64",
+        sym::log10f128 => "llvm.log10.f128",
+
+        sym::log2f16 => "llvm.log2.f16",
         sym::log2f32 => "llvm.log2.f32",
         sym::log2f64 => "llvm.log2.f64",
+        sym::log2f128 => "llvm.log2.f128",
+
+        sym::fmaf16 => "llvm.fma.f16",
         sym::fmaf32 => "llvm.fma.f32",
         sym::fmaf64 => "llvm.fma.f64",
+        sym::fmaf128 => "llvm.fma.f128",
+
+        sym::fabsf16 => "llvm.fabs.f16",
         sym::fabsf32 => "llvm.fabs.f32",
         sym::fabsf64 => "llvm.fabs.f64",
+        sym::fabsf128 => "llvm.fabs.f128",
+
+        sym::minnumf16 => "llvm.minnum.f16",
         sym::minnumf32 => "llvm.minnum.f32",
         sym::minnumf64 => "llvm.minnum.f64",
+        sym::minnumf128 => "llvm.minnum.f128",
+
+        sym::maxnumf16 => "llvm.maxnum.f16",
         sym::maxnumf32 => "llvm.maxnum.f32",
         sym::maxnumf64 => "llvm.maxnum.f64",
+        sym::maxnumf128 => "llvm.maxnum.f128",
+
+        sym::copysignf16 => "llvm.copysign.f16",
         sym::copysignf32 => "llvm.copysign.f32",
         sym::copysignf64 => "llvm.copysign.f64",
+        sym::copysignf128 => "llvm.copysign.f128",
+
+        sym::floorf16 => "llvm.floor.f16",
         sym::floorf32 => "llvm.floor.f32",
         sym::floorf64 => "llvm.floor.f64",
+        sym::floorf128 => "llvm.floor.f128",
+
+        sym::ceilf16 => "llvm.ceil.f16",
         sym::ceilf32 => "llvm.ceil.f32",
         sym::ceilf64 => "llvm.ceil.f64",
+        sym::ceilf128 => "llvm.ceil.f128",
+
+        sym::truncf16 => "llvm.trunc.f16",
         sym::truncf32 => "llvm.trunc.f32",
         sym::truncf64 => "llvm.trunc.f64",
+        sym::truncf128 => "llvm.trunc.f128",
+
+        sym::rintf16 => "llvm.rint.f16",
         sym::rintf32 => "llvm.rint.f32",
         sym::rintf64 => "llvm.rint.f64",
+        sym::rintf128 => "llvm.rint.f128",
+
+        sym::nearbyintf16 => "llvm.nearbyint.f16",
         sym::nearbyintf32 => "llvm.nearbyint.f32",
         sym::nearbyintf64 => "llvm.nearbyint.f64",
+        sym::nearbyintf128 => "llvm.nearbyint.f128",
+
+        sym::roundf16 => "llvm.round.f16",
         sym::roundf32 => "llvm.round.f32",
         sym::roundf64 => "llvm.round.f64",
+        sym::roundf128 => "llvm.round.f128",
+
         sym::ptr_mask => "llvm.ptrmask",
+
+        sym::roundevenf16 => "llvm.roundeven.f16",
         sym::roundevenf32 => "llvm.roundeven.f32",
         sym::roundevenf64 => "llvm.roundeven.f64",
+        sym::roundevenf128 => "llvm.roundeven.f128",
+
         _ => return None,
     };
     Some(cx.get_intrinsic(llvm_name))
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 3c20b579349..f4e83330874 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -480,6 +480,9 @@ pub struct SanitizerOptions {
     pub sanitize_address: bool,
     pub sanitize_address_recover: bool,
     pub sanitize_cfi: bool,
+    pub sanitize_dataflow: bool,
+    pub sanitize_dataflow_abilist: *const *const c_char,
+    pub sanitize_dataflow_abilist_len: size_t,
     pub sanitize_kcfi: bool,
     pub sanitize_memory: bool,
     pub sanitize_memory_recover: bool,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 0c77f7c51bc..fcb3602b734 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1221,6 +1221,9 @@ fn add_sanitizer_libraries(
     if sanitizer.contains(SanitizerSet::ADDRESS) {
         link_sanitizer_runtime(sess, flavor, linker, "asan");
     }
+    if sanitizer.contains(SanitizerSet::DATAFLOW) {
+        link_sanitizer_runtime(sess, flavor, linker, "dfsan");
+    }
     if sanitizer.contains(SanitizerSet::LEAK) {
         link_sanitizer_runtime(sess, flavor, linker, "lsan");
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 97089dff31b..60865d06ab9 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -95,6 +95,7 @@ pub struct ModuleConfig {
 
     pub sanitizer: SanitizerSet,
     pub sanitizer_recover: SanitizerSet,
+    pub sanitizer_dataflow_abilist: Vec<String>,
     pub sanitizer_memory_track_origins: usize,
 
     // Flags indicating which outputs to produce.
@@ -197,6 +198,10 @@ impl ModuleConfig {
             ),
 
             sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
+            sanitizer_dataflow_abilist: if_regular!(
+                sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
+                Vec::new()
+            ),
             sanitizer_recover: if_regular!(
                 sess.opts.unstable_opts.sanitizer_recover,
                 SanitizerSet::empty()
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index 265ca0c7884..3ea54146fc7 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -4,7 +4,7 @@
 //! other areas of the compiler as well.
 
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::traits::{DefiningAnchor, ObligationCause};
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance};
 use rustc_trait_selection::traits::ObligationCtxt;
 
@@ -33,9 +33,6 @@ pub fn is_equal_up_to_subtyping<'tcx>(
 /// When validating assignments, the variance should be `Covariant`. When checking
 /// during `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial)` variance should be `Invariant`
 /// because we want to check for type equality.
-///
-/// This mostly ignores opaque types as it can be used in constraining contexts
-/// while still computing the final underlying type.
 pub fn relate_types<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
@@ -47,8 +44,7 @@ pub fn relate_types<'tcx>(
         return true;
     }
 
-    let mut builder =
-        tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
+    let mut builder = tcx.infer_ctxt().ignoring_regions();
     let infcx = builder.build();
     let ocx = ObligationCtxt::new(&infcx);
     let cause = ObligationCause::dummy();
@@ -58,20 +54,5 @@ pub fn relate_types<'tcx>(
         Ok(()) => {}
         Err(_) => return false,
     };
-    let errors = ocx.select_all_or_error();
-    // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing`
-    // we would get unification errors because we're unable to look into opaque types,
-    // even if they're constrained in our current function.
-    for (key, ty) in infcx.take_opaque_types() {
-        let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
-        if hidden_ty != ty.hidden_type.ty {
-            span_bug!(
-                ty.hidden_type.span,
-                "{}, {}",
-                tcx.type_of(key.def_id).instantiate(tcx, key.args),
-                ty.hidden_type.ty
-            );
-        }
-    }
-    errors.is_empty()
+    ocx.select_all_or_error().is_empty()
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 78e7c636a3e..3dac6880f17 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2460,6 +2460,7 @@ impl PrimTy {
         Self::Uint(UintTy::Usize),
         Self::Float(FloatTy::F32),
         Self::Float(FloatTy::F64),
+        // FIXME(f16_f128): add these when enabled below
         Self::Bool,
         Self::Char,
         Self::Str,
@@ -2509,6 +2510,10 @@ impl PrimTy {
             sym::usize => Self::Uint(UintTy::Usize),
             sym::f32 => Self::Float(FloatTy::F32),
             sym::f64 => Self::Float(FloatTy::F64),
+            // FIXME(f16_f128): enabling these will open the gates of f16 and f128 being
+            // understood by rustc.
+            // sym::f16 => Self::Float(FloatTy::F16),
+            // sym::f128 => Self::Float(FloatTy::F128),
             sym::bool => Self::Bool,
             sym::char => Self::Char,
             sym::str => Self::Str,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 6e9b4236e20..9d8eb6ad60b 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -112,11 +112,15 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::likely
         | sym::unlikely
         | sym::ptr_guaranteed_cmp
+        | sym::minnumf16
         | sym::minnumf32
         | sym::minnumf64
+        | sym::minnumf128
+        | sym::maxnumf16
         | sym::maxnumf32
-        | sym::rustc_peek
         | sym::maxnumf64
+        | sym::maxnumf128
+        | sym::rustc_peek
         | sym::type_name
         | sym::forget
         | sym::black_box
@@ -302,50 +306,118 @@ pub fn check_intrinsic_type(
                 ],
                 Ty::new_unit(tcx),
             ),
+
+            sym::sqrtf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::sqrtf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::sqrtf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::sqrtf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::powif16 => (0, 0, vec![tcx.types.f16, tcx.types.i32], tcx.types.f16),
             sym::powif32 => (0, 0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
             sym::powif64 => (0, 0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
+            sym::powif128 => (0, 0, vec![tcx.types.f128, tcx.types.i32], tcx.types.f128),
+
+            sym::sinf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::sinf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::sinf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::sinf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::cosf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::cosf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::cosf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::cosf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::powf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::powf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::powf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::powf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
+            sym::expf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::expf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::expf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::expf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::exp2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::exp2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::exp2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::exp2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::logf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::logf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::logf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::logf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::log10f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::log10f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::log10f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::log10f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::log2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::log2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::log2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::log2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::fmaf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::fmaf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::fmaf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::fmaf128 => {
+                (0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128)
+            }
+
+            sym::fabsf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::fabsf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::fabsf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::fabsf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::minnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::minnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
+            sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
+            sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::copysignf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
+            sym::floorf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::floorf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::floorf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::floorf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::ceilf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::ceilf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::ceilf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::ceilf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::truncf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::truncf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::truncf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::truncf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::rintf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::rintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::rintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::rintf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::nearbyintf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::nearbyintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::nearbyintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::nearbyintf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::roundf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::roundf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::roundf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::roundf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
+
+            sym::roundevenf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
             sym::roundevenf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
             sym::roundevenf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::roundevenf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
 
             sym::volatile_load | sym::unaligned_volatile_load => {
                 (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0))
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 112553b2f70..5e1fc248b80 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -811,6 +811,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(sanitizer_cfi_canonical_jump_tables, None);
     tracked!(sanitizer_cfi_generalize_pointers, Some(true));
     tracked!(sanitizer_cfi_normalize_integers, Some(true));
+    tracked!(sanitizer_dataflow_abilist, vec![String::from("/rustc/abc")]);
     tracked!(sanitizer_memory_track_origins, 2);
     tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
     tracked!(saturating_float_casts, Some(true));
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 5b1cc52f1f6..4ec784e2590 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -42,6 +42,7 @@
 #endif
 #include "llvm/Transforms/Instrumentation.h"
 #include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
+#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
 #include "llvm/Support/TimeProfiler.h"
 #if LLVM_VERSION_GE(19, 0)
 #include "llvm/Support/PGOOptions.h"
@@ -686,6 +687,9 @@ struct LLVMRustSanitizerOptions {
   bool SanitizeAddress;
   bool SanitizeAddressRecover;
   bool SanitizeCFI;
+  bool SanitizeDataFlow;
+  char **SanitizeDataFlowABIList;
+  size_t SanitizeDataFlowABIListLen;
   bool SanitizeKCFI;
   bool SanitizeMemory;
   bool SanitizeMemoryRecover;
@@ -883,6 +887,18 @@ LLVMRustOptimize(
   }
 
   if (SanitizerOptions) {
+    if (SanitizerOptions->SanitizeDataFlow) {
+      std::vector<std::string> ABIListFiles(
+          SanitizerOptions->SanitizeDataFlowABIList,
+          SanitizerOptions->SanitizeDataFlowABIList +
+              SanitizerOptions->SanitizeDataFlowABIListLen);
+      OptimizerLastEPCallbacks.push_back(
+        [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) {
+          MPM.addPass(DataFlowSanitizerPass(ABIListFiles));
+        }
+      );
+    }
+
     if (SanitizerOptions->SanitizeMemory) {
       MemorySanitizerOptions Options(
           SanitizerOptions->SanitizeMemoryTrackOrigins,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6fdb03c0bab..f005a240504 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1991,8 +1991,10 @@ pub fn uint_ty(uty: ast::UintTy) -> UintTy {
 
 pub fn float_ty(fty: ast::FloatTy) -> FloatTy {
     match fty {
+        ast::FloatTy::F16 => FloatTy::F16,
         ast::FloatTy::F32 => FloatTy::F32,
         ast::FloatTy::F64 => FloatTy::F64,
+        ast::FloatTy::F128 => FloatTy::F128,
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index daa0349789e..a6273b92e5d 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -701,7 +701,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.bind_pattern(
             self.source_info(irrefutable_pat.span),
             candidate,
-            &fake_borrow_temps,
+            fake_borrow_temps.as_slice(),
             irrefutable_pat.span,
             None,
             false,
@@ -1938,7 +1938,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let post_guard_block = self.bind_pattern(
             self.source_info(pat.span),
             guard_candidate,
-            &fake_borrow_temps,
+            fake_borrow_temps.as_slice(),
             expr_span,
             None,
             false,
@@ -2425,7 +2425,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let matching = this.bind_pattern(
                 this.source_info(pattern.span),
                 candidate,
-                &fake_borrow_temps,
+                fake_borrow_temps.as_slice(),
                 initializer_span,
                 None,
                 true,
@@ -2434,7 +2434,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let failure = this.bind_pattern(
                 this.source_info(else_block_span),
                 wildcard,
-                &fake_borrow_temps,
+                fake_borrow_temps.as_slice(),
                 initializer_span,
                 None,
                 true,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index c610f85fd5f..a3fccb7c319 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -41,60 +41,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         //     let y = x;
         // }
         //
-        // We can't just reverse the binding order, because we must preserve pattern-order
-        // otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first,
-        // and bindings at the same depth stay in source order.
-        //
-        // To do this, every time around the loop we prepend the newly found bindings to the
-        // bindings we already had.
-        //
-        // example:
-        // candidate.bindings = [1, 2, 3]
-        // bindings in iter 1: [4, 5]
-        // bindings in iter 2: [6, 7]
-        //
-        // final bindings: [6, 7, 4, 5, 1, 2, 3]
-        let mut accumulated_bindings = mem::take(candidate_bindings);
-        let mut simplified_match_pairs = Vec::new();
-        // Repeatedly simplify match pairs until we're left with only unsimplifiable ones.
-        loop {
-            for mut match_pair in mem::take(match_pairs) {
-                if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
-                    if let Some(binding) = binding {
-                        candidate_bindings.push(binding);
-                    }
-                    if let Some(ascription) = ascription {
-                        candidate_ascriptions.push(ascription);
-                    }
-                    // Simplifiable pattern; we replace it with its subpairs and simplify further.
-                    match_pairs.append(&mut match_pair.subpairs);
-                } else {
-                    // Unsimplifiable pattern; we recursively simplify its subpairs and don't
-                    // process it further.
-                    self.simplify_match_pairs(
-                        &mut match_pair.subpairs,
-                        candidate_bindings,
-                        candidate_ascriptions,
-                    );
-                    simplified_match_pairs.push(match_pair);
+        // We therefore lower bindings from left-to-right, except we lower the `x` in `x @ pat`
+        // after any bindings in `pat`. This doesn't work for or-patterns: the current structure of
+        // match lowering forces us to lower bindings inside or-patterns last.
+        for mut match_pair in mem::take(match_pairs) {
+            self.simplify_match_pairs(
+                &mut match_pair.subpairs,
+                candidate_bindings,
+                candidate_ascriptions,
+            );
+            if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
+                if let Some(binding) = binding {
+                    candidate_bindings.push(binding);
                 }
-            }
-
-            // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
-            candidate_bindings.extend_from_slice(&accumulated_bindings);
-            mem::swap(candidate_bindings, &mut accumulated_bindings);
-            candidate_bindings.clear();
-
-            if match_pairs.is_empty() {
-                break;
+                if let Some(ascription) = ascription {
+                    candidate_ascriptions.push(ascription);
+                }
+                // Simplifiable pattern; we replace it with its already simplified subpairs.
+                match_pairs.append(&mut match_pair.subpairs);
+            } else {
+                // Unsimplifiable pattern; we keep it.
+                match_pairs.push(match_pair);
             }
         }
 
-        // Store computed bindings back in `candidate_bindings`.
-        mem::swap(candidate_bindings, &mut accumulated_bindings);
-        // Store simplified match pairs back in `match_pairs`.
-        mem::swap(match_pairs, &mut simplified_match_pairs);
-
         // Move or-patterns to the end, because they can result in us
         // creating additional candidates, so we want to test them as
         // late as possible.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 743f4760339..42c9d5e10eb 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -371,7 +371,8 @@ mod desc {
     pub const parse_list: &str = "a space-separated list of strings";
     pub const parse_list_with_polarity: &str =
         "a comma-separated list of strings, with elements beginning with + or -";
-    pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
+    pub const parse_comma_list: &str = "a comma-separated list of strings";
+    pub const parse_opt_comma_list: &str = parse_comma_list;
     pub const parse_number: &str = "a number";
     pub const parse_opt_number: &str = parse_number;
     pub const parse_threads: &str = parse_number;
@@ -381,7 +382,7 @@ mod desc {
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_oom_strategy: &str = "either `panic` or `abort`";
     pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
+    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
     pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
     pub const parse_cfguard: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -602,6 +603,18 @@ mod parse {
         }
     }
 
+    pub(crate) fn parse_comma_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
+                v.sort_unstable();
+                *slot = v;
+                true
+            }
+            None => false,
+        }
+    }
+
     pub(crate) fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
@@ -718,6 +731,7 @@ mod parse {
                 *slot |= match s {
                     "address" => SanitizerSet::ADDRESS,
                     "cfi" => SanitizerSet::CFI,
+                    "dataflow" => SanitizerSet::DATAFLOW,
                     "kcfi" => SanitizerSet::KCFI,
                     "kernel-address" => SanitizerSet::KERNELADDRESS,
                     "leak" => SanitizerSet::LEAK,
@@ -1846,6 +1860,8 @@ written to standard error output)"),
         "enable generalizing pointer types (default: no)"),
     sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable normalizing integer types (default: no)"),
+    sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
+        "additional ABI list files that control how shadow parameters are passed (comma separated)"),
     sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
         "enable origins tracking in MemorySanitizer"),
     sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 2e86a8bd581..ee8d9ae9c53 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -490,6 +490,8 @@ symbols! {
         catch_unwind,
         cause,
         cdylib,
+        ceilf128,
+        ceilf16,
         ceilf32,
         ceilf64,
         cfg,
@@ -595,6 +597,8 @@ symbols! {
         copy,
         copy_closures,
         copy_nonoverlapping,
+        copysignf128,
+        copysignf16,
         copysignf32,
         copysignf64,
         core,
@@ -607,6 +611,8 @@ symbols! {
         coroutine_resume,
         coroutine_state,
         coroutines,
+        cosf128,
+        cosf16,
         cosf32,
         cosf64,
         count,
@@ -737,10 +743,14 @@ symbols! {
         exhaustive_integer_patterns,
         exhaustive_patterns,
         existential_type,
+        exp2f128,
+        exp2f16,
         exp2f32,
         exp2f64,
         expect,
         expected,
+        expf128,
+        expf16,
         expf32,
         expf64,
         explicit_generic_args_with_impl_trait,
@@ -759,7 +769,9 @@ symbols! {
         external_doc,
         f,
         f128,
+        f128_nan,
         f16,
+        f16_nan,
         f16c_target_feature,
         f32,
         f32_legacy_const_digits,
@@ -793,6 +805,8 @@ symbols! {
         f64_legacy_const_neg_infinity,
         f64_legacy_const_radix,
         f64_nan,
+        fabsf128,
+        fabsf16,
         fabsf32,
         fabsf64,
         fadd_algebraic,
@@ -813,8 +827,12 @@ symbols! {
         file,
         float,
         float_to_int_unchecked,
+        floorf128,
+        floorf16,
         floorf32,
         floorf64,
+        fmaf128,
+        fmaf16,
         fmaf32,
         fmaf64,
         fmt,
@@ -1030,11 +1048,17 @@ symbols! {
         loaded_from_disk,
         local,
         local_inner_macros,
+        log10f128,
+        log10f16,
         log10f32,
         log10f64,
+        log2f128,
+        log2f16,
         log2f32,
         log2f64,
         log_syntax,
+        logf128,
+        logf16,
         logf32,
         logf64,
         loongarch_target_feature,
@@ -1062,6 +1086,8 @@ symbols! {
         match_beginning_vert,
         match_default_bindings,
         matches_macro,
+        maxnumf128,
+        maxnumf16,
         maxnumf32,
         maxnumf64,
         may_dangle,
@@ -1093,6 +1119,8 @@ symbols! {
         min_exhaustive_patterns,
         min_specialization,
         min_type_alias_impl_trait,
+        minnumf128,
+        minnumf16,
         minnumf32,
         minnumf64,
         mips_target_feature,
@@ -1155,6 +1183,8 @@ symbols! {
         native_link_modifiers_whole_archive,
         natvis_file,
         ne,
+        nearbyintf128,
+        nearbyintf16,
         nearbyintf32,
         nearbyintf64,
         needs_allocator,
@@ -1289,8 +1319,12 @@ symbols! {
         poll_next,
         post_dash_lto: "post-lto",
         powerpc_target_feature,
+        powf128,
+        powf16,
         powf32,
         powf64,
+        powif128,
+        powif16,
         powif32,
         powif64,
         pre_dash_lto: "pre-lto",
@@ -1416,6 +1450,8 @@ symbols! {
         return_position_impl_trait_in_trait,
         return_type_notation,
         rhs,
+        rintf128,
+        rintf16,
         rintf32,
         rintf64,
         riscv_target_feature,
@@ -1424,8 +1460,12 @@ symbols! {
         ropi_rwpi: "ropi-rwpi",
         rotate_left,
         rotate_right,
+        roundevenf128,
+        roundevenf16,
         roundevenf32,
         roundevenf64,
+        roundf128,
+        roundf16,
         roundf32,
         roundf64,
         rt,
@@ -1630,6 +1670,8 @@ symbols! {
         simd_trunc,
         simd_xor,
         since,
+        sinf128,
+        sinf16,
         sinf32,
         sinf64,
         size,
@@ -1647,6 +1689,8 @@ symbols! {
         specialization,
         speed,
         spotlight,
+        sqrtf128,
+        sqrtf16,
         sqrtf32,
         sqrtf64,
         sreg,
@@ -1746,6 +1790,8 @@ symbols! {
         transparent_enums,
         transparent_unions,
         trivial_bounds,
+        truncf128,
+        truncf16,
         truncf32,
         truncf64,
         try_blocks,
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 87422042180..51e2c96120c 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -464,16 +464,17 @@ fn encode_ty<'tcx>(
             typeid.push_str(&s);
         }
 
-        // Rust's f32 and f64 single (32-bit) and double (64-bit) precision floating-point types
-        // have IEEE-754 binary32 and binary64 floating-point layouts, respectively.
+        // Rust's f16, f32, f64, and f126 half (16-bit), single (32-bit), double (64-bit), and
+        // quad (128-bit)  precision floating-point types have IEEE-754 binary16, binary32,
+        // binary64, and binary128 floating-point layouts, respectively.
         //
         // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#fixed-width-floating-point-types.)
         ty::Float(float_ty) => {
-            typeid.push(match float_ty {
-                FloatTy::F16 => unimplemented!("f16_f128"),
-                FloatTy::F32 => 'f',
-                FloatTy::F64 => 'd',
-                FloatTy::F128 => unimplemented!("f16_f128"),
+            typeid.push_str(match float_ty {
+                FloatTy::F16 => "Dh",
+                FloatTy::F32 => "f",
+                FloatTy::F64 => "d",
+                FloatTy::F128 => "g",
             });
         }
 
@@ -557,7 +558,7 @@ fn encode_ty<'tcx>(
                         // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
                         let builtin_types = [
                             "v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m", "x", "y",
-                            "n", "o", "f", "d", "e", "g", "z",
+                            "n", "o", "f", "d", "e", "g", "z", "Dh",
                         ];
                         if !builtin_types.contains(&str) {
                             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 747c945960a..f1b1b4ed2bb 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -320,8 +320,11 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             ty::Uint(UintTy::U64) => "y",
             ty::Uint(UintTy::U128) => "o",
             ty::Uint(UintTy::Usize) => "j",
+            // FIXME(f16_f128): update these once `rustc-demangle` supports the new types
+            ty::Float(FloatTy::F16) => unimplemented!("f16_f128"),
             ty::Float(FloatTy::F32) => "f",
             ty::Float(FloatTy::F64) => "d",
+            ty::Float(FloatTy::F128) => unimplemented!("f16_f128"),
             ty::Never => "z",
 
             // Placeholders (should be demangled as `_`).
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 651d5632277..9f68e3602a0 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1221,6 +1221,7 @@ bitflags::bitflags! {
         const KCFI    = 1 << 8;
         const KERNELADDRESS = 1 << 9;
         const SAFESTACK = 1 << 10;
+        const DATAFLOW = 1 << 11;
     }
 }
 rustc_data_structures::external_bitflags_debug! { SanitizerSet }
@@ -1233,6 +1234,7 @@ impl SanitizerSet {
         Some(match self {
             SanitizerSet::ADDRESS => "address",
             SanitizerSet::CFI => "cfi",
+            SanitizerSet::DATAFLOW => "dataflow",
             SanitizerSet::KCFI => "kcfi",
             SanitizerSet::KERNELADDRESS => "kernel-address",
             SanitizerSet::LEAK => "leak",
@@ -2790,6 +2792,7 @@ impl Target {
                             base.$key_name |= match s.as_str() {
                                 Some("address") => SanitizerSet::ADDRESS,
                                 Some("cfi") => SanitizerSet::CFI,
+                                Some("dataflow") => SanitizerSet::DATAFLOW,
                                 Some("kcfi") => SanitizerSet::KCFI,
                                 Some("kernel-address") => SanitizerSet::KERNELADDRESS,
                                 Some("leak") => SanitizerSet::LEAK,
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
index 2296b58f45d..1510f3b390c 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
@@ -10,6 +10,7 @@ pub fn target() -> Target {
     base.static_position_independent_executables = true;
     base.supported_sanitizers = SanitizerSet::ADDRESS
         | SanitizerSet::CFI
+        | SanitizerSet::DATAFLOW
         | SanitizerSet::LEAK
         | SanitizerSet::MEMORY
         | SanitizerSet::SAFESTACK
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index b214f4946b1..b40768a52b6 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -136,6 +136,15 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
 #[inline(always)]
 fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
     // Increment the reference count of the arc to clone it.
+    //
+    // The #[inline(always)] is to ensure that raw_waker and clone_waker are
+    // always generated in the same code generation unit as one another, and
+    // therefore that the structurally identical const-promoted RawWakerVTable
+    // within both functions is deduplicated at LLVM IR code generation time.
+    // This allows optimizing Waker::will_wake to a single pointer comparison of
+    // the vtable pointers, rather than comparing all four function pointers
+    // within the vtables.
+    #[inline(always)]
     unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
         unsafe { Arc::increment_strong_count(waker as *const W) };
         RawWaker::new(
@@ -304,6 +313,10 @@ impl<W: LocalWake + 'static> From<Rc<W>> for RawWaker {
 #[inline(always)]
 fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
     // Increment the reference count of the Rc to clone it.
+    //
+    // Refer to the comment on raw_waker's clone_waker regarding why this is
+    // always inline.
+    #[inline(always)]
     unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker {
         unsafe { Rc::increment_strong_count(waker as *const W) };
         RawWaker::new(
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index c4e89a58a05..ed928994ad6 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -41,6 +41,7 @@
 #![feature(thin_box)]
 #![feature(strict_provenance)]
 #![feature(drain_keep_rest)]
+#![feature(local_waker)]
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
@@ -62,6 +63,7 @@ mod rc;
 mod slice;
 mod str;
 mod string;
+mod task;
 mod thin_box;
 mod vec;
 mod vec_deque;
diff --git a/library/alloc/tests/task.rs b/library/alloc/tests/task.rs
new file mode 100644
index 00000000000..0f8d9218980
--- /dev/null
+++ b/library/alloc/tests/task.rs
@@ -0,0 +1,34 @@
+use alloc::rc::Rc;
+use alloc::sync::Arc;
+use alloc::task::{LocalWake, Wake};
+use core::task::{LocalWaker, Waker};
+
+#[test]
+fn test_waker_will_wake_clone() {
+    struct NoopWaker;
+
+    impl Wake for NoopWaker {
+        fn wake(self: Arc<Self>) {}
+    }
+
+    let waker = Waker::from(Arc::new(NoopWaker));
+    let clone = waker.clone();
+
+    assert!(waker.will_wake(&clone));
+    assert!(clone.will_wake(&waker));
+}
+
+#[test]
+fn test_local_waker_will_wake_clone() {
+    struct NoopWaker;
+
+    impl LocalWake for NoopWaker {
+        fn wake(self: Rc<Self>) {}
+    }
+
+    let waker = LocalWaker::from(Rc::new(NoopWaker));
+    let clone = waker.clone();
+
+    assert!(waker.will_wake(&clone));
+    assert!(clone.will_wake(&waker));
+}
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index d34c19a47e3..8b65e8ff9c3 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -48,7 +48,7 @@ o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests")
 o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
 o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
 o("vendor", "build.vendor", "enable usage of vendored Rust crates")
-o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
+o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)")
 o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
 o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
 o("profiler", "build.profiler", "build the profiler runtime")
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index 9998fe2f5db..bd1f9699c3c 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/116881
+Last change is for: https://github.com/rust-lang/rust/pull/120761
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 0681289a94f..701bd585eee 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -1088,7 +1088,7 @@ fn supported_sanitizers(
         "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
         "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
         "x86_64-unknown-linux-gnu" => {
-            common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"])
+            common_libs("linux", "x86_64", &["asan", "dfsan", "lsan", "msan", "safestack", "tsan"])
         }
         "x86_64-unknown-linux-musl" => {
             common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 523617eb3e1..c8fd154a00e 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -29,6 +29,8 @@ This feature allows for use of one of following sanitizers:
 * Those that apart from testing, may be used in production:
   * [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity
     (CFI) provides forward-edge control flow protection.
+  * [DataFlowSanitizer](#dataflowsanitizer) a generic dynamic data flow analysis
+    framework.
   * [KernelControlFlowIntegrity](#kernelcontrolflowintegrity) LLVM Kernel
     Control Flow Integrity (KCFI) provides forward-edge control flow protection
     for operating systems kernels.
@@ -39,14 +41,21 @@ This feature allows for use of one of following sanitizers:
   * [ShadowCallStack](#shadowcallstack) provides backward-edge control flow
     protection (aarch64 only).
 
-To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
-`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
-`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
-You might also need the `--target` and `build-std` flags. Example:
+To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`,
+`-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
+`-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
+`-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
+
+Example:
 ```shell
 $ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
 ```
 
+Additional options for sanitizers can be passed to LLVM command line argument
+processor via LLVM arguments using `llvm-args` codegen option (e.g.,
+`-Cllvm-args=-dfsan-combine-pointer-labels-on-load=false`). See the sanitizer
+documentation for more information about additional options.
+
 # AddressSanitizer
 
 AddressSanitizer is a memory error detector. It can detect the following types
@@ -639,6 +648,21 @@ LLVM KCFI is supported on the following targets:
 See the [Clang KernelControlFlowIntegrity documentation][clang-kcfi] for more
 details.
 
+# DataFlowSanitizer
+
+DataFlowSanitizer is a generalised dynamic data flow analysis.
+
+Unlike other Sanitizer tools, this tool is not designed to detect a specific
+class of bugs on its own. Instead, it provides a generic dynamic data flow
+analysis framework to be used by clients to help detect application-specific
+issues within their own code.
+
+DataFlowSanitizer is supported on the following targets:
+
+* `x86_64-unknown-linux-gnu`
+
+See the [Clang DataFlowSanitizer documentation][clang-dataflow] for more details.
+
 # KernelAddressSanitizer
 
 KernelAddressSanitizer (KASAN) is a freestanding version of AddressSanitizer
@@ -849,6 +873,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 * [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
 * [AddressSanitizer in Clang][clang-asan]
 * [ControlFlowIntegrity in Clang][clang-cfi]
+* [DataFlowSanitizer in Clang][clang-dataflow]
 * [HWAddressSanitizer in Clang][clang-hwasan]
 * [Linux Kernel's KernelAddressSanitizer documentation][linux-kasan]
 * [LeakSanitizer in Clang][clang-lsan]
@@ -858,6 +883,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 
 [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
 [clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
+[clang-dataflow]: https://clang.llvm.org/docs/DataFlowSanitizer.html
 [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
 [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 1707b514ef8..c35baeb4cf5 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1777,8 +1777,10 @@ impl PrimitiveType {
             hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
             hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
             hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
+            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
             hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
             hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
+            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
             hir::PrimTy::Str => PrimitiveType::Str,
             hir::PrimTy::Bool => PrimitiveType::Bool,
             hir::PrimTy::Char => PrimitiveType::Char,
@@ -1977,8 +1979,10 @@ impl From<ast::UintTy> for PrimitiveType {
 impl From<ast::FloatTy> for PrimitiveType {
     fn from(float_ty: ast::FloatTy) -> PrimitiveType {
         match float_ty {
+            ast::FloatTy::F16 => PrimitiveType::F16,
             ast::FloatTy::F32 => PrimitiveType::F32,
             ast::FloatTy::F64 => PrimitiveType::F64,
+            ast::FloatTy::F128 => PrimitiveType::F128,
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 409ae0c85ac..25606f4253e 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -75,9 +75,12 @@ impl ApproxConstant {
     fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
         match *lit {
             LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
+                FloatTy::F16 => self.check_known_consts(cx, e, s, "f16"),
                 FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"),
                 FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"),
+                FloatTy::F128 => self.check_known_consts(cx, e, s, "f128"),
             },
+            // FIXME(f16_f128): add `f16` and `f128` when these types become stable.
             LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"),
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index cffca952e47..07fbb1cb5c9 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -76,8 +76,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
             let digits = count_digits(sym_str);
             let max = max_digits(fty);
             let type_suffix = match lit_float_ty {
+                LitFloatType::Suffixed(ast::FloatTy::F16) => Some("f16"),
                 LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
                 LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
+                LitFloatType::Suffixed(ast::FloatTy::F128) => Some("f128"),
                 LitFloatType::Unsuffixed => None,
             };
             let (is_whole, is_inf, mut float_str) = match fty {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 1f2b2d54efd..07ed4fbbf8e 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -277,12 +277,16 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n.get()),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
+            ast::FloatTy::F16 => unimplemented!("f16_f128"),
             ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
             ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
+            ast::FloatTy::F128 => unimplemented!("f16_f128"),
         },
         LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
+            ty::Float(FloatTy::F16) => unimplemented!("f16_f128"),
             ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
             ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
+            ty::Float(FloatTy::F128) => unimplemented!("f16_f128"),
             _ => bug!(),
         },
         LitKind::Bool(b) => Constant::Bool(b),
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 49f1226e2cc..bfe6c959e7c 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -156,6 +156,7 @@ impl PanicStrategy {
 pub enum Sanitizer {
     Address,
     Cfi,
+    Dataflow,
     Kcfi,
     KernelAddress,
     Leak,
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 9b22b2112a8..39786588150 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -30,6 +30,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored on targets without CFI sanitizer",
         },
         Need {
+            name: "needs-sanitizer-dataflow",
+            condition: cache.sanitizer_dataflow,
+            ignore_reason: "ignored on targets without dataflow sanitizer",
+        },
+        Need {
             name: "needs-sanitizer-kcfi",
             condition: cache.sanitizer_kcfi,
             ignore_reason: "ignored on targets without kernel CFI sanitizer",
@@ -190,6 +195,7 @@ pub(super) struct CachedNeedsConditions {
     sanitizer_support: bool,
     sanitizer_address: bool,
     sanitizer_cfi: bool,
+    sanitizer_dataflow: bool,
     sanitizer_kcfi: bool,
     sanitizer_kasan: bool,
     sanitizer_leak: bool,
@@ -229,6 +235,7 @@ impl CachedNeedsConditions {
             sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
             sanitizer_address: sanitizers.contains(&Sanitizer::Address),
             sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi),
+            sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow),
             sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi),
             sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress),
             sanitizer_leak: sanitizers.contains(&Sanitizer::Leak),
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 920fe16a9fc..8899a55b2df 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -43,6 +43,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
     "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
     "tests/ui/proc-macro/auxiliary/included-file.txt", // more include
     "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
+    "tests/ui/sanitizer/dataflow-abilist.txt", // dataflow sanitizer ABI list file
     "tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file
     "tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file
     "tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file
diff --git a/tests/codegen/sanitizer/dataflow-instrument-functions.rs b/tests/codegen/sanitizer/dataflow-instrument-functions.rs
new file mode 100644
index 00000000000..69c3560882c
--- /dev/null
+++ b/tests/codegen/sanitizer/dataflow-instrument-functions.rs
@@ -0,0 +1,10 @@
+// Verifies that functions are instrumented.
+//
+//@ needs-sanitizer-dataflow
+//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow
+
+#![crate_type="lib"]
+
+pub fn foo() {
+}
+// CHECK: define{{.*}}foo{{.*}}.dfsan
diff --git a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
index 8b427cff677..7a374c5675a 100644
--- a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
@@ -51,13 +51,13 @@
 -     }
 - 
 -     bb3: {
-          StorageLive(_9);
-          _9 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
           StorageLive(_8);
           _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_9);
+          _9 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
           _0 = const 0_u32;
-          StorageDead(_8);
           StorageDead(_9);
+          StorageDead(_8);
 -         goto -> bb4;
 +         goto -> bb3;
       }
diff --git a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
index 32a8dd8b8b4..95bcfe71792 100644
--- a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
@@ -57,13 +57,13 @@
 -     }
 - 
 -     bb4: {
-          StorageLive(_10);
-          _10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
           StorageLive(_9);
           _9 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_10);
+          _10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
           _0 = const 0_u32;
-          StorageDead(_9);
           StorageDead(_10);
+          StorageDead(_9);
 -         goto -> bb6;
 +         goto -> bb4;
       }
diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
index cc16af721ca..e058c409cb5 100644
--- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
@@ -51,13 +51,13 @@
 -     }
 - 
 -     bb3: {
-          StorageLive(_9);
-          _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool);
           StorageLive(_8);
           _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_9);
+          _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool);
           _0 = const 0_u32;
-          StorageDead(_8);
           StorageDead(_9);
+          StorageDead(_8);
 -         goto -> bb4;
 +         goto -> bb3;
       }
diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
index eb8926d27ee..f98d68e6ffc 100644
--- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
@@ -69,16 +69,16 @@
   
 -     bb4: {
 +     bb3: {
-          StorageLive(_13);
-          _13 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
-          StorageLive(_12);
-          _12 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
           StorageLive(_11);
           _11 = (((_4.0: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_12);
+          _12 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_13);
+          _13 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
           _0 = const 0_u32;
-          StorageDead(_11);
-          StorageDead(_12);
           StorageDead(_13);
+          StorageDead(_12);
+          StorageDead(_11);
 -         goto -> bb5;
 +         goto -> bb4;
       }
diff --git a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
index 6179bab11fe..a5b5659a31a 100644
--- a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
@@ -116,12 +116,12 @@
       }
   
       bb6: {
-          StorageLive(_13);
-          _39 = deref_copy (_4.1: &ViewportPercentageLength);
-          _13 = (((*_39) as Vw).0: f32);
           StorageLive(_12);
-          _40 = deref_copy (_4.0: &ViewportPercentageLength);
-          _12 = (((*_40) as Vw).0: f32);
+          _39 = deref_copy (_4.0: &ViewportPercentageLength);
+          _12 = (((*_39) as Vw).0: f32);
+          StorageLive(_13);
+          _40 = deref_copy (_4.1: &ViewportPercentageLength);
+          _13 = (((*_40) as Vw).0: f32);
           StorageLive(_14);
           StorageLive(_15);
           _15 = _12;
@@ -132,18 +132,18 @@
           StorageDead(_15);
           _3 = ViewportPercentageLength::Vw(move _14);
           StorageDead(_14);
-          StorageDead(_12);
           StorageDead(_13);
+          StorageDead(_12);
           goto -> bb10;
       }
   
       bb7: {
-          StorageLive(_18);
-          _41 = deref_copy (_4.1: &ViewportPercentageLength);
-          _18 = (((*_41) as Vh).0: f32);
           StorageLive(_17);
-          _42 = deref_copy (_4.0: &ViewportPercentageLength);
-          _17 = (((*_42) as Vh).0: f32);
+          _41 = deref_copy (_4.0: &ViewportPercentageLength);
+          _17 = (((*_41) as Vh).0: f32);
+          StorageLive(_18);
+          _42 = deref_copy (_4.1: &ViewportPercentageLength);
+          _18 = (((*_42) as Vh).0: f32);
           StorageLive(_19);
           StorageLive(_20);
           _20 = _17;
@@ -154,18 +154,18 @@
           StorageDead(_20);
           _3 = ViewportPercentageLength::Vh(move _19);
           StorageDead(_19);
-          StorageDead(_17);
           StorageDead(_18);
+          StorageDead(_17);
           goto -> bb10;
       }
   
       bb8: {
-          StorageLive(_23);
-          _43 = deref_copy (_4.1: &ViewportPercentageLength);
-          _23 = (((*_43) as Vmin).0: f32);
           StorageLive(_22);
-          _44 = deref_copy (_4.0: &ViewportPercentageLength);
-          _22 = (((*_44) as Vmin).0: f32);
+          _43 = deref_copy (_4.0: &ViewportPercentageLength);
+          _22 = (((*_43) as Vmin).0: f32);
+          StorageLive(_23);
+          _44 = deref_copy (_4.1: &ViewportPercentageLength);
+          _23 = (((*_44) as Vmin).0: f32);
           StorageLive(_24);
           StorageLive(_25);
           _25 = _22;
@@ -176,18 +176,18 @@
           StorageDead(_25);
           _3 = ViewportPercentageLength::Vmin(move _24);
           StorageDead(_24);
-          StorageDead(_22);
           StorageDead(_23);
+          StorageDead(_22);
           goto -> bb10;
       }
   
       bb9: {
-          StorageLive(_28);
-          _45 = deref_copy (_4.1: &ViewportPercentageLength);
-          _28 = (((*_45) as Vmax).0: f32);
           StorageLive(_27);
-          _46 = deref_copy (_4.0: &ViewportPercentageLength);
-          _27 = (((*_46) as Vmax).0: f32);
+          _45 = deref_copy (_4.0: &ViewportPercentageLength);
+          _27 = (((*_45) as Vmax).0: f32);
+          StorageLive(_28);
+          _46 = deref_copy (_4.1: &ViewportPercentageLength);
+          _28 = (((*_46) as Vmax).0: f32);
           StorageLive(_29);
           StorageLive(_30);
           _30 = _27;
@@ -198,8 +198,8 @@
           StorageDead(_30);
           _3 = ViewportPercentageLength::Vmax(move _29);
           StorageDead(_29);
-          StorageDead(_27);
           StorageDead(_28);
+          StorageDead(_27);
           goto -> bb10;
       }
   
diff --git a/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
index d7908ab3cd2..7fdd8554e38 100644
--- a/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
@@ -59,13 +59,13 @@
       }
   
       bb5: {
-          StorageLive(_10);
-          _10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
           StorageLive(_9);
           _9 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_10);
+          _10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
           _0 = const 0_u32;
-          StorageDead(_9);
           StorageDead(_10);
+          StorageDead(_9);
           goto -> bb8;
       }
   
diff --git a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
index ea5cd55b560..596dcef85fd 100644
--- a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
@@ -19,8 +19,7 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
 
     bb0: {
         PlaceMention(_1);
-        _2 = discriminant((_1.2: std::option::Option<i32>));
-        switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
+        switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1];
     }
 
     bb1: {
@@ -29,11 +28,12 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
     }
 
     bb2: {
-        switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb3, 8: bb3, otherwise: bb1];
+        _2 = discriminant((_1.2: std::option::Option<i32>));
+        switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1];
     }
 
     bb3: {
-        switchInt((_1.0: u32)) -> [1: bb4, 4: bb4, otherwise: bb1];
+        switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1];
     }
 
     bb4: {
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 5dda4931d54..01fc3f83f16 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -100,7 +100,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     sanitize = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `sanitize` are: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
+   = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr
index 39bf2214232..01c5a553dc5 100644
--- a/tests/ui/impl-trait/hidden-type-is-opaque-2.stderr
+++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:8:17
+  --> $DIR/hidden-type-is-opaque-2.rs:10:17
    |
 LL |     Thunk::new(|mut cont| {
    |                 ^^^^^^^^
@@ -13,7 +13,7 @@ LL |     Thunk::new(|mut cont: /* Type */| {
    |                         ++++++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/hidden-type-is-opaque-2.rs:18:17
+  --> $DIR/hidden-type-is-opaque-2.rs:20:17
    |
 LL |     Thunk::new(|mut cont| {
    |                 ^^^^^^^^
diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr
new file mode 100644
index 00000000000..01c5a553dc5
--- /dev/null
+++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr
@@ -0,0 +1,31 @@
+error[E0282]: type annotations needed
+  --> $DIR/hidden-type-is-opaque-2.rs:10:17
+   |
+LL |     Thunk::new(|mut cont| {
+   |                 ^^^^^^^^
+LL |
+LL |         cont.reify_as();
+   |         ---- type must be known at this point
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     Thunk::new(|mut cont: /* Type */| {
+   |                         ++++++++++++
+
+error[E0282]: type annotations needed
+  --> $DIR/hidden-type-is-opaque-2.rs:20:17
+   |
+LL |     Thunk::new(|mut cont| {
+   |                 ^^^^^^^^
+LL |
+LL |         cont.reify_as();
+   |         ---- type must be known at this point
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     Thunk::new(|mut cont: /* Type */| {
+   |                         ++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.rs b/tests/ui/impl-trait/hidden-type-is-opaque-2.rs
index 212e7b10802..78ac8363ba9 100644
--- a/tests/ui/impl-trait/hidden-type-is-opaque-2.rs
+++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.rs
@@ -1,6 +1,8 @@
 // This doesn't work, because we don't flow information from opaque types
 // into function arguments via the function's generic parameters
 // FIXME(oli-obk): make `expected_inputs_for_expected_output` support this
+//@ revisions: default next
+//@[next] compile-flags: -Znext-solver
 
 #![feature(type_alias_impl_trait)]
 
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs b/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs
new file mode 100644
index 00000000000..1555da2fd1f
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs
@@ -0,0 +1,17 @@
+//@ known-bug: unknown
+#![allow(unused)]
+
+struct A(u32);
+
+pub fn main() {
+    // The or-pattern bindings are lowered after `x`, which triggers the error.
+    let x @ (A(a) | A(a)) = A(10);
+    // ERROR: use of moved value
+    assert!(x.0 == 10);
+    assert!(a == 10);
+
+    // This works.
+    let (x @ A(a) | x @ A(a)) = A(10);
+    assert!(x.0 == 10);
+    assert!(a == 10);
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.stderr b/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.stderr
new file mode 100644
index 00000000000..79808186358
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.stderr
@@ -0,0 +1,31 @@
+error[E0382]: use of moved value
+  --> $DIR/bind-by-copy-or-pat.rs:8:16
+   |
+LL |     let x @ (A(a) | A(a)) = A(10);
+   |         -      ^            ----- move occurs because value has type `A`, which does not implement the `Copy` trait
+   |         |      |
+   |         |      value used here after move
+   |         value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref x @ (A(a) | A(a)) = A(10);
+   |         +++
+
+error[E0382]: use of moved value
+  --> $DIR/bind-by-copy-or-pat.rs:8:23
+   |
+LL |     let x @ (A(a) | A(a)) = A(10);
+   |         -             ^     ----- move occurs because value has type `A`, which does not implement the `Copy` trait
+   |         |             |
+   |         |             value used here after move
+   |         value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref x @ (A(a) | A(a)) = A(10);
+   |         +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/sanitizer/dataflow-abilist.txt b/tests/ui/sanitizer/dataflow-abilist.txt
new file mode 100644
index 00000000000..fe04838f549
--- /dev/null
+++ b/tests/ui/sanitizer/dataflow-abilist.txt
@@ -0,0 +1,505 @@
+fun:main=uninstrumented
+fun:main=discard
+
+###############################################################################
+# DFSan interface functions
+###############################################################################
+fun:dfsan_union=uninstrumented
+fun:dfsan_union=discard
+fun:dfsan_create_label=uninstrumented
+fun:dfsan_create_label=discard
+fun:dfsan_set_label=uninstrumented
+fun:dfsan_set_label=discard
+fun:dfsan_add_label=uninstrumented
+fun:dfsan_add_label=discard
+fun:dfsan_get_label=uninstrumented
+fun:dfsan_get_label=custom
+fun:dfsan_read_label=uninstrumented
+fun:dfsan_read_label=discard
+fun:dfsan_get_label_count=uninstrumented
+fun:dfsan_get_label_count=discard
+fun:dfsan_get_label_info=uninstrumented
+fun:dfsan_get_label_info=discard
+fun:dfsan_has_label=uninstrumented
+fun:dfsan_has_label=discard
+fun:dfsan_has_label_with_desc=uninstrumented
+fun:dfsan_has_label_with_desc=discard
+fun:dfsan_set_write_callback=uninstrumented
+fun:dfsan_set_write_callback=custom
+fun:dfsan_flush=uninstrumented
+fun:dfsan_flush=discard
+fun:dfsan_print_origin_trace=uninstrumented
+fun:dfsan_print_origin_trace=discard
+fun:dfsan_print_origin_id_trace=uninstrumented
+fun:dfsan_print_origin_id_trace=discard
+fun:dfsan_sprint_origin_trace=uninstrumented
+fun:dfsan_sprint_origin_trace=discard
+fun:dfsan_sprint_origin_id_trace=uninstrumented
+fun:dfsan_sprint_origin_id_trace=discard
+fun:dfsan_sprint_stack_trace=uninstrumented
+fun:dfsan_sprint_stack_trace=discard
+fun:dfsan_get_origin=uninstrumented
+fun:dfsan_get_origin=custom
+fun:dfsan_read_origin_of_first_taint=uninstrumented
+fun:dfsan_read_origin_of_first_taint=discard
+fun:dfsan_get_init_origin=uninstrumented
+fun:dfsan_get_init_origin=discard
+fun:dfsan_get_track_origins=uninstrumented
+fun:dfsan_get_track_origins=discard
+fun:dfsan_set_conditional_callback=uninstrumented
+fun:dfsan_set_conditional_callback=discard
+fun:dfsan_get_labels_in_signal_conditional=uninstrumented
+fun:dfsan_get_labels_in_signal_conditional=discard
+fun:dfsan_set_reaches_function_callback=uninstrumented
+fun:dfsan_set_reaches_function_callback=discard
+fun:dfsan_get_labels_in_signal_reaches_function=uninstrumented
+fun:dfsan_get_labels_in_signal_reaches_function=discard
+fun:dfsan_reaches_function_callback=uninstrumented
+fun:dfsan_reaches_function_callback=discard
+
+###############################################################################
+# glibc
+###############################################################################
+# Functions of memory allocators
+fun:__libc_memalign=discard
+fun:aligned_alloc=discard
+fun:calloc=discard
+fun:cfree=discard
+fun:mallinfo=discard
+fun:malloc=discard
+fun:free=discard
+fun:malloc_stats=discard
+fun:malloc_usable_size=discard
+fun:mallopt=discard
+fun:memalign=discard
+fun:posix_memalign=discard
+fun:pvalloc=discard
+fun:realloc=discard
+fun:reallocarray=discard
+fun:valloc=discard
+
+# Functions that return a value that depends on the input, but the output might
+# not be necessarily data-dependent on the input.
+fun:isalpha=functional
+fun:isdigit=functional
+fun:isprint=functional
+fun:isxdigit=functional
+fun:isalnum=functional
+fun:ispunct=functional
+fun:isspace=functional
+fun:tolower=functional
+fun:_tolower=functional
+fun:toupper=functional
+
+# Functions that return a value that is data-dependent on the input.
+fun:__isinf=functional
+fun:__isinff=functional
+fun:__signbit=functional
+fun:__signbitf=functional
+fun:__signbitl=functional
+fun:btowc=functional
+fun:exp=functional
+fun:exp2=functional
+fun:expf=functional
+fun:expl=functional
+fun:fabs=functional
+fun:finite=functional
+fun:finitef=functional
+fun:finitel=functional
+fun:floor=functional
+fun:fmod=functional
+fun:isinf=functional
+fun:isinff=functional
+fun:isinfl=functional
+fun:isnan=functional
+fun:isnanf=functional
+fun:isnanl=functional
+fun:log=functional
+fun:log1p=functional
+fun:log1pf=functional
+fun:log1pl=functional
+fun:log2=functional
+fun:log2f=functional
+fun:log2l=functional
+fun:modf=functional
+fun:nextafter=functional
+fun:nextafterf=functional
+fun:nextafterl=functional
+fun:nexttoward=functional
+fun:nexttowardf=functional
+fun:nexttowardl=functional
+fun:pow=functional
+fun:powf=functional
+fun:powl=functional
+fun:round=functional
+fun:sqrt=functional
+fun:sqrtf=functional
+fun:sqrtl=functional
+fun:wctob=functional
+
+# Functions that produce an output that does not depend on the input (shadow is
+# zeroed automatically).
+fun:__assert_fail=discard
+fun:__cmsg_nxthdr=discard
+fun:__ctype_b_loc=discard
+fun:__cxa_atexit=discard
+fun:__errno_location=discard
+fun:__newlocale=discard
+fun:__sbrk=discard
+fun:__sigsetjmp=discard
+fun:__uselocale=discard
+fun:__wctype_l=discard
+fun:access=discard
+fun:alarm=discard
+fun:atexit=discard
+fun:bind=discard
+fun:chdir=discard
+fun:close=discard
+fun:closedir=discard
+fun:connect=discard
+fun:creat=discard
+fun:dladdr=discard
+fun:dlclose=discard
+fun:epoll_create=discard
+fun:epoll_create1=discard
+fun:epoll_ctl=discard
+fun:fclose=discard
+fun:feof=discard
+fun:ferror=discard
+fun:fflush=discard
+fun:fileno=discard
+fun:fopen=discard
+fun:fprintf=discard
+fun:fputc=discard
+fun:fputc=discard
+fun:fputs=discard
+fun:fputs=discard
+fun:fseek=discard
+fun:ftell=discard
+fun:fwrite=discard
+fun:getenv=discard
+fun:getuid=discard
+fun:geteuid=discard
+fun:getpagesize=discard
+fun:getpid=discard
+fun:kill=discard
+fun:listen=discard
+fun:lseek=discard
+fun:mkdir=discard
+fun:mmap=discard
+fun:munmap=discard
+fun:open=discard
+fun:openat=discard
+fun:pipe=discard
+fun:posix_fadvise=discard
+fun:prctl=discard
+fun:printf=discard
+fun:pthread_sigmask=discard
+fun:putc=discard
+fun:putchar=discard
+fun:puts=discard
+fun:rand=discard
+fun:random=discard
+fun:remove=discard
+fun:sched_getcpu=discard
+fun:sched_get_priority_max=discard
+fun:sched_setaffinity=discard
+fun:sched_yield=discard
+fun:sem_destroy=discard
+fun:sem_init=discard
+fun:sem_post=discard
+fun:sem_wait=discard
+fun:send=discard
+fun:sendmsg=discard
+fun:sendto=discard
+fun:setsockopt=discard
+fun:shutdown=discard
+fun:sleep=discard
+fun:socket=discard
+fun:strerror=discard
+fun:strspn=discard
+fun:strcspn=discard
+fun:symlink=discard
+fun:syscall=discard
+fun:unlink=discard
+fun:uselocale=discard
+fun:vfprintf=discard
+
+# Functions that produce output does not depend on the input (need to zero the
+# shadow manually).
+fun:_dl_get_tls_static_info=custom
+fun:clock_gettime=custom
+fun:dlopen=custom
+fun:epoll_wait=custom
+fun:fgets=custom
+fun:fstat=custom
+fun:getcwd=custom
+fun:get_current_dir_name=custom
+fun:getentropy=custom
+fun:gethostname=custom
+fun:getpeername=custom
+fun:getrlimit=custom
+fun:getrusage=custom
+fun:getsockname=custom
+fun:getsockopt=custom
+fun:nanosleep=custom
+fun:pread=custom
+fun:read=custom
+fun:recvmmsg=custom
+fun:recvmsg=custom
+fun:sigaltstack=custom
+fun:socketpair=custom
+fun:stat=custom
+fun:time=custom
+
+# Functions that produce an output that depend on the input (propagate the
+# shadow manually).
+fun:ctime_r=custom
+fun:inet_pton=custom
+fun:localtime_r=custom
+fun:memcpy=custom
+fun:memmove=custom
+fun:memset=custom
+fun:strcpy=custom
+fun:strdup=custom
+fun:strncpy=custom
+fun:strtod=custom
+fun:strtol=custom
+fun:strtoll=custom
+fun:strtoul=custom
+fun:strtoull=custom
+fun:strcat=custom
+fun:strncat=custom
+fun:__isoc23_strtod=custom
+fun:__isoc23_strtol=custom
+fun:__isoc23_strtoll=custom
+fun:__isoc23_strtoul=custom
+fun:__isoc23_strtoull=custom
+
+# Functions that produce an output that is computed from the input, but is not
+# necessarily data dependent.
+fun:bcmp=custom
+fun:memchr=custom
+fun:memcmp=custom
+fun:strcasecmp=custom
+fun:strchr=custom
+fun:strcmp=custom
+fun:strlen=custom
+fun:strnlen=custom
+fun:strncasecmp=custom
+fun:strncmp=custom
+fun:strpbrk=custom
+fun:strrchr=custom
+fun:strstr=custom
+fun:strsep=custom
+
+# Functions which take action based on global state, such as running a callback
+# set by a separate function.
+fun:write=custom
+
+# Functions that take a callback (wrap the callback manually).
+fun:dl_iterate_phdr=custom
+
+fun:getpwuid_r=custom
+fun:poll=custom
+fun:sched_getaffinity=custom
+fun:select=custom
+fun:sigemptyset=custom
+fun:sigaction=custom
+fun:signal=custom
+fun:gettimeofday=custom
+
+# sprintf-like
+fun:sprintf=custom
+fun:snprintf=custom
+
+# scanf-like
+fun:sscanf=custom
+fun:__isoc99_sscanf=custom
+fun:__isoc23_sscanf=custom
+
+# TODO: custom
+fun:asprintf=discard
+fun:qsort=discard
+
+# fork
+fun:fork=custom
+
+###############################################################################
+# pthread
+###############################################################################
+fun:__pthread_register_cancel=discard
+fun:__pthread_unregister_cancel=discard
+fun:pthread_attr_destroy=discard
+fun:pthread_attr_getaffinity_np=discard
+fun:pthread_attr_getdetachstate=discard
+fun:pthread_attr_getguardsize=discard
+fun:pthread_attr_getinheritsched=discard
+fun:pthread_attr_getschedparam=discard
+fun:pthread_attr_getschedpolicy=discard
+fun:pthread_attr_getscope=discard
+fun:pthread_attr_getstack=discard
+fun:pthread_attr_getstackaddr=disacrd
+fun:pthread_attr_getstacksize=discard
+fun:pthread_attr_init=discard
+fun:pthread_attr_setaffinity_np=discard
+fun:pthread_attr_setdetachstate=discard
+fun:pthread_attr_setguardsize=discard
+fun:pthread_attr_setinheritsched=discard
+fun:pthread_attr_setschedparam=discard
+fun:pthread_attr_setschedpolicy=discard
+fun:pthread_attr_setscope=discard
+fun:pthread_attr_setstack=discard
+fun:pthread_attr_setstackaddr=discard
+fun:pthread_attr_setstacksize=discard
+fun:pthread_equal=discard
+fun:pthread_getschedparam=discard
+fun:pthread_getspecific=discard
+fun:pthread_key_create=discard
+fun:pthread_key_delete=discard
+fun:pthread_mutex_destroy=discard
+fun:pthread_mutex_init=discard
+fun:pthread_mutex_lock=discard
+fun:pthread_mutex_trylock=discard
+fun:pthread_mutex_unlock=discard
+fun:pthread_mutexattr_destroy=discard
+fun:pthread_mutexattr_init=discard
+fun:pthread_mutexattr_settype=discard
+fun:pthread_rwlock_destroy=discard
+fun:pthread_rwlock_init=discard
+fun:pthread_rwlock_rdlock=discard
+fun:pthread_rwlock_timedrdlock=discard
+fun:pthread_rwlock_timedwrlock=discard
+fun:pthread_rwlock_tryrdlock=discard
+fun:pthread_rwlock_trywrlock=discard
+fun:pthread_rwlock_wrlock=discard
+fun:pthread_rwlock_unlock=discard
+fun:pthread_setschedparam=discard
+fun:pthread_setname_np=discard
+fun:pthread_once=discard
+fun:pthread_self=discard
+fun:pthread_setspecific=discard
+
+# Functions that take a callback (wrap the callback manually).
+fun:pthread_create=custom
+
+# Functions that produce output does not depend on the input (need to zero the
+# shadow manually).
+fun:pthread_join=custom
+
+###############################################################################
+# libffi/libgo
+###############################################################################
+# Functions that are written in asm or are called from asm.
+fun:ffi_call_unix64=uninstrumented
+fun:ffi_call_unix64=discard
+fun:ffi_closure_unix64_inner=uninstrumented
+fun:ffi_closure_unix64_inner=discard
+fun:ffi_closure_unix64=uninstrumented
+fun:ffi_closure_unix64=discard
+fun:__go_get_closure=uninstrumented
+fun:__go_get_closure=discard
+fun:__go_makefunc_can_recover=uninstrumented
+fun:__go_makefunc_can_recover=discard
+fun:__go_makefunc_returning=uninstrumented
+fun:__go_makefunc_returning=discard
+fun:reflect.MakeFuncStubGo=uninstrumented
+fun:reflect.MakeFuncStubGo=discard
+fun:reflect.makeFuncStub=uninstrumented
+fun:reflect.makeFuncStub=discard
+
+
+###############################################################################
+# lib/Fuzzer
+###############################################################################
+# Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp
+fun:__sanitizer_cov_trace_cmp1=custom
+fun:__sanitizer_cov_trace_cmp1=uninstrumented
+fun:__sanitizer_cov_trace_cmp2=custom
+fun:__sanitizer_cov_trace_cmp2=uninstrumented
+fun:__sanitizer_cov_trace_cmp4=custom
+fun:__sanitizer_cov_trace_cmp4=uninstrumented
+fun:__sanitizer_cov_trace_cmp8=custom
+fun:__sanitizer_cov_trace_cmp8=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp1=custom
+fun:__sanitizer_cov_trace_const_cmp1=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp2=custom
+fun:__sanitizer_cov_trace_const_cmp2=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp4=custom
+fun:__sanitizer_cov_trace_const_cmp4=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp8=custom
+fun:__sanitizer_cov_trace_const_cmp8=uninstrumented
+# Similar for __sanitizer_cov_trace_switch
+fun:__sanitizer_cov_trace_switch=custom
+fun:__sanitizer_cov_trace_switch=uninstrumented
+
+# Ignores all other __sanitizer callbacks.
+fun:__sanitizer_cov=uninstrumented
+fun:__sanitizer_cov=discard
+fun:__sanitizer_cov_module_init=uninstrumented
+fun:__sanitizer_cov_module_init=discard
+fun:__sanitizer_cov_with_check=uninstrumented
+fun:__sanitizer_cov_with_check=discard
+fun:__sanitizer_set_death_callback=uninstrumented
+fun:__sanitizer_set_death_callback=discard
+fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
+fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
+fun:__sanitizer_cov_trace_pc*=uninstrumented
+fun:__sanitizer_cov_trace_pc*=discard
+fun:__sanitizer_cov_pcs_init=uninstrumented
+fun:__sanitizer_cov_pcs_init=discard
+
+fun:__sanitizer_get_current_allocated_bytes=uninstrumented
+fun:__sanitizer_get_current_allocated_bytes=discard
+fun:__sanitizer_get_heap_size=uninstrumented
+fun:__sanitizer_get_heap_size=discard
+fun:__sanitizer_get_free_bytes=uninstrumented
+fun:__sanitizer_get_free_bytes=discard
+fun:__sanitizer_get_unmapped_bytes=uninstrumented
+fun:__sanitizer_get_unmapped_bytes=discard
+fun:__sanitizer_get_estimated_allocated_size=uninstrumented
+fun:__sanitizer_get_estimated_allocated_size=discard
+fun:__sanitizer_get_ownership=uninstrumented
+fun:__sanitizer_get_ownership=discard
+fun:__sanitizer_get_allocated_begin=uninstrumented
+fun:__sanitizer_get_allocated_begin=discard
+fun:__sanitizer_get_allocated_size=uninstrumented
+fun:__sanitizer_get_allocated_size=discard
+fun:__sanitizer_get_allocated_size_fast=uninstrumented
+fun:__sanitizer_get_allocated_size_fast=discard
+fun:__sanitizer_print_stack_trace=uninstrumented
+fun:__sanitizer_print_stack_trace=discard
+
+fun:TcmallocSlab_Internal_PushBatch_FixedShift=uninstrumented
+fun:TcmallocSlab_Internal_PushBatch_FixedShift=discard
+fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=uninstrumented
+fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=discard
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64=uninstrumented
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64=discard
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=uninstrumented
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=discard
+fun:TcmallocSlab_Internal_PopBatch_FixedShift=uninstrumented
+fun:TcmallocSlab_Internal_PopBatch_FixedShift=discard
+fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=uninstrumented
+fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=discard
+
+# Ignores the dfsan wrappers.
+fun:__dfsw_*=uninstrumented
+fun:__dfsw_*=discard
+fun:__dfso_*=uninstrumented
+fun:__dfso_*=discard
+
+# Rust functions.
+fun:__rdl_alloc=uninstrumented
+fun:__rdl_alloc_zeroed=uninstrumented
+fun:__rdl_dealloc=uninstrumented
+fun:__rdl_realloc=uninstrumented
+fun:__rg_oom=uninstrumented
+fun:__rust_alloc=uninstrumented
+fun:__rust_alloc_error_handler=uninstrumented
+fun:__rust_alloc_zeroed=uninstrumented
+fun:__rust_dealloc=uninstrumented
+fun:__rust_realloc=uninstrumented
+fun:_ZN4core*=uninstrumented
+fun:_ZN3std*=uninstrumented
+fun:rust_eh_personality=uninstrumented
diff --git a/tests/ui/sanitizer/dataflow.rs b/tests/ui/sanitizer/dataflow.rs
new file mode 100644
index 00000000000..658a9e48086
--- /dev/null
+++ b/tests/ui/sanitizer/dataflow.rs
@@ -0,0 +1,60 @@
+#![allow(non_camel_case_types)]
+// Verifies that labels are propagated through loads and stores.
+//
+//@ needs-sanitizer-support
+//@ needs-sanitizer-dataflow
+//@ run-pass
+//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt
+
+use std::mem::size_of;
+use std::os::raw::{c_int, c_long, c_void};
+
+type dfsan_label = u8;
+
+extern "C" {
+    fn dfsan_add_label(label: dfsan_label, addr: *mut c_void, size: usize);
+    fn dfsan_get_label(data: c_long) -> dfsan_label;
+    fn dfsan_has_label(label: dfsan_label, elem: dfsan_label) -> c_int;
+    fn dfsan_read_label(addr: *const c_void, size: usize) -> dfsan_label;
+    fn dfsan_set_label(label: dfsan_label, addr: *mut c_void, size: usize);
+}
+
+fn propagate2(i: &i64) -> i64 {
+    i.clone()
+}
+
+fn propagate(i: i64) -> i64 {
+    let v = vec!(i, 1, 2, 3);
+    let j = v.iter().sum();
+    propagate2(&j)
+}
+
+pub fn main() {
+    let mut i = 1i64;
+    let i_ptr = &mut i as *mut i64;
+    let i_label: dfsan_label = 1;
+    unsafe {
+        dfsan_set_label(i_label, i_ptr as *mut c_void, size_of::<i64>());
+    }
+
+    let new_label = unsafe { dfsan_get_label(i) };
+    assert_eq!(i_label, new_label);
+
+    let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
+    assert_eq!(i_label, read_label);
+
+    let j_label: dfsan_label = 2;
+    unsafe {
+        dfsan_add_label(j_label, i_ptr as *mut c_void, size_of::<i64>());
+    }
+
+    let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
+    assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
+    assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
+
+    let mut new_i = propagate(i);
+    let new_i_ptr = &mut new_i as *mut i64;
+    let read_label = unsafe { dfsan_read_label(new_i_ptr as *const c_void, size_of::<i64>()) };
+    assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
+    assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
+}