about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-08 20:38:48 +0000
committerbors <bors@rust-lang.org>2024-07-08 20:38:48 +0000
commit35b658fb1071d752d092751d9f17a9fa7b154ec4 (patch)
treea8defb834692240de591c1aa1460ac9a65f41d76
parent32e692681e457b06efedd05c5a4be0d718f39292 (diff)
parent72199b2c52916edca9f585877608a156b313d66b (diff)
downloadrust-35b658fb1071d752d092751d9f17a9fa7b154ec4.tar.gz
rust-35b658fb1071d752d092751d9f17a9fa7b154ec4.zip
Auto merge of #127489 - GuillaumeGomez:rollup-rhqfeom, r=GuillaumeGomez
Rollup of 4 pull requests

Successful merges:

 - #126427 (Rewrite `intrinsic-unreachable`, `sepcomp-cci-copies`, `sepcomp-inlining` and `sepcomp-separate` `run-make` tests to rmake.rs)
 - #127237 (Improve code of `run-make/llvm-ident`)
 - #127325 (Migrate `target-cpu-native`,  `target-specs` and `target-without-atomic-cas` `run-make` tests to rmake)
 - #127482 (Infer async closure signature from (old-style) two-part `Fn` + `Future` bounds)

Failed merges:

 - #127357 (Remove `StructuredDiag`)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs102
-rw-r--r--src/tools/run-make-support/src/fs_wrapper.rs20
-rw-r--r--src/tools/run-make-support/src/lib.rs14
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt7
-rw-r--r--tests/run-make/intrinsic-unreachable/Makefile12
-rw-r--r--tests/run-make/intrinsic-unreachable/rmake.rs20
-rw-r--r--tests/run-make/llvm-ident/rmake.rs22
-rw-r--r--tests/run-make/sepcomp-cci-copies/Makefile12
-rw-r--r--tests/run-make/sepcomp-cci-copies/rmake.rs17
-rw-r--r--tests/run-make/sepcomp-inlining/Makefile15
-rw-r--r--tests/run-make/sepcomp-inlining/rmake.rs23
-rw-r--r--tests/run-make/sepcomp-separate/Makefile9
-rw-r--r--tests/run-make/sepcomp-separate/rmake.rs15
-rw-r--r--tests/run-make/target-cpu-native/Makefile20
-rw-r--r--tests/run-make/target-cpu-native/rmake.rs14
-rw-r--r--tests/run-make/target-specs/Makefile12
-rw-r--r--tests/run-make/target-specs/rmake.rs71
-rw-r--r--tests/run-make/target-without-atomic-cas/Makefile5
-rw-r--r--tests/run-make/target-without-atomic-cas/rmake.rs16
-rw-r--r--tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs27
20 files changed, 329 insertions, 124 deletions
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index ac7ed3e26f9..53cf121dfeb 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -424,9 +424,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let Some(trait_def_id) = trait_def_id {
                 let found_kind = match closure_kind {
                     hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
-                    hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
-                        self.tcx.async_fn_trait_kind_from_def_id(trait_def_id)
-                    }
+                    hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self
+                        .tcx
+                        .async_fn_trait_kind_from_def_id(trait_def_id)
+                        .or_else(|| self.tcx.fn_trait_kind_from_def_id(trait_def_id)),
                     _ => None,
                 };
 
@@ -470,14 +471,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // for closures and async closures, respectively.
         match closure_kind {
             hir::ClosureKind::Closure
-                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
+                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+            {
+                self.extract_sig_from_projection(cause_span, projection)
+            }
+            hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
+                if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+            {
+                self.extract_sig_from_projection(cause_span, projection)
+            }
+            // It's possible we've passed the closure to a (somewhat out-of-fashion)
+            // `F: FnOnce() -> Fut, Fut: Future<Output = T>` style bound. Let's still
+            // guide inference here, since it's beneficial for the user.
             hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
-                if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
-            _ => return None,
+                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+            {
+                self.extract_sig_from_projection_and_future_bound(cause_span, projection)
+            }
+            _ => None,
         }
+    }
+
+    /// Given an `FnOnce::Output` or `AsyncFn::Output` projection, extract the args
+    /// and return type to infer a [`ty::PolyFnSig`] for the closure.
+    fn extract_sig_from_projection(
+        &self,
+        cause_span: Option<Span>,
+        projection: ty::PolyProjectionPredicate<'tcx>,
+    ) -> Option<ExpectedSig<'tcx>> {
+        let projection = self.resolve_vars_if_possible(projection);
 
         let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1);
-        let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
         debug!(?arg_param_ty);
 
         let ty::Tuple(input_tys) = *arg_param_ty.kind() else {
@@ -486,7 +510,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Since this is a return parameter type it is safe to unwrap.
         let ret_param_ty = projection.skip_binder().term.expect_type();
-        let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
         debug!(?ret_param_ty);
 
         let sig = projection.rebind(self.tcx.mk_fn_sig(
@@ -500,6 +523,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         Some(ExpectedSig { cause_span, sig })
     }
 
+    /// When an async closure is passed to a function that has a "two-part" `Fn`
+    /// and `Future` trait bound, like:
+    ///
+    /// ```rust
+    /// use std::future::Future;
+    ///
+    /// fn not_exactly_an_async_closure<F, Fut>(_f: F)
+    /// where
+    ///     F: FnOnce(String, u32) -> Fut,
+    ///     Fut: Future<Output = i32>,
+    /// {}
+    /// ```
+    ///
+    /// The we want to be able to extract the signature to guide inference in the async
+    /// closure. We will have two projection predicates registered in this case. First,
+    /// we identify the `FnOnce<Args, Output = ?Fut>` bound, and if the output type is
+    /// an inference variable `?Fut`, we check if that is bounded by a `Future<Output = Ty>`
+    /// projection.
+    fn extract_sig_from_projection_and_future_bound(
+        &self,
+        cause_span: Option<Span>,
+        projection: ty::PolyProjectionPredicate<'tcx>,
+    ) -> Option<ExpectedSig<'tcx>> {
+        let projection = self.resolve_vars_if_possible(projection);
+
+        let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1);
+        debug!(?arg_param_ty);
+
+        let ty::Tuple(input_tys) = *arg_param_ty.kind() else {
+            return None;
+        };
+
+        // If the return type is a type variable, look for bounds on it.
+        // We could theoretically support other kinds of return types here,
+        // but none of them would be useful, since async closures return
+        // concrete anonymous future types, and their futures are not coerced
+        // into any other type within the body of the async closure.
+        let ty::Infer(ty::TyVar(return_vid)) = *projection.skip_binder().term.expect_type().kind()
+        else {
+            return None;
+        };
+
+        // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare.
+        for bound in self.obligations_for_self_ty(return_vid) {
+            if let Some(ret_projection) = bound.predicate.as_projection_clause()
+                && let Some(ret_projection) = ret_projection.no_bound_vars()
+                && self.tcx.is_lang_item(ret_projection.def_id(), LangItem::FutureOutput)
+            {
+                let sig = projection.rebind(self.tcx.mk_fn_sig(
+                    input_tys,
+                    ret_projection.term.expect_type(),
+                    false,
+                    hir::Safety::Safe,
+                    Abi::Rust,
+                ));
+
+                return Some(ExpectedSig { cause_span, sig });
+            }
+        }
+
+        None
+    }
+
     fn sig_of_closure(
         &self,
         expr_def_id: LocalDefId,
diff --git a/src/tools/run-make-support/src/fs_wrapper.rs b/src/tools/run-make-support/src/fs_wrapper.rs
index 8a2bfce8b4a..0f0d6f6618c 100644
--- a/src/tools/run-make-support/src/fs_wrapper.rs
+++ b/src/tools/run-make-support/src/fs_wrapper.rs
@@ -1,7 +1,7 @@
 use std::fs;
 use std::path::Path;
 
-/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message.
 #[track_caller]
 pub fn remove_file<P: AsRef<Path>>(path: P) {
     fs::remove_file(path.as_ref())
@@ -18,21 +18,21 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
     ));
 }
 
-/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_file<P: AsRef<Path>>(path: P) {
     fs::File::create(path.as_ref())
         .expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display()));
 }
 
-/// A wrapper around [`std::fs::read`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
     fs::read(path.as_ref())
         .expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display()))
 }
 
-/// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
     fs::read_to_string(path.as_ref()).expect(&format!(
@@ -41,14 +41,14 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
     ))
 }
 
-/// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read_dir<P: AsRef<Path>>(path: P) -> fs::ReadDir {
     fs::read_dir(path.as_ref())
         .expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display()))
 }
 
-/// A wrapper around [`std::fs::write`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::write`] which includes the file path in the panic message.
 #[track_caller]
 pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
     fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
@@ -57,7 +57,7 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
     ));
 }
 
-/// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message.
 #[track_caller]
 pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
     fs::remove_dir_all(path.as_ref()).expect(&format!(
@@ -66,7 +66,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_dir<P: AsRef<Path>>(path: P) {
     fs::create_dir(path.as_ref()).expect(&format!(
@@ -75,7 +75,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_dir_all<P: AsRef<Path>>(path: P) {
     fs::create_dir_all(path.as_ref()).expect(&format!(
@@ -84,7 +84,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message.
 #[track_caller]
 pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata {
     fs::metadata(path.as_ref()).expect(&format!(
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index f464a109e77..3fdf94804f1 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -303,6 +303,20 @@ pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, exp
         .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned()))
 }
 
+/// Gathers all files in the current working directory that have the extension `ext`, and counts
+/// the number of lines within that contain a match with the regex pattern `re`.
+pub fn count_regex_matches_in_files_with_extension(re: &regex::Regex, ext: &str) -> usize {
+    let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext));
+
+    let mut count = 0;
+    for file in fetched_files {
+        let content = fs_wrapper::read_to_string(file);
+        count += content.lines().filter(|line| re.is_match(&line)).count();
+    }
+
+    count
+}
+
 /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
 /// available on the platform!
 #[track_caller]
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 31cb32d349a..e658621ab88 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -47,7 +47,6 @@ run-make/foreign-rust-exceptions/Makefile
 run-make/incr-add-rust-src-component/Makefile
 run-make/incr-foreign-head-span/Makefile
 run-make/interdependent-c-libraries/Makefile
-run-make/intrinsic-unreachable/Makefile
 run-make/issue-107094/Makefile
 run-make/issue-109934-lto-debuginfo/Makefile
 run-make/issue-14698/Makefile
@@ -130,9 +129,6 @@ run-make/rustc-macro-dep-files/Makefile
 run-make/sanitizer-cdylib-link/Makefile
 run-make/sanitizer-dylib-link/Makefile
 run-make/sanitizer-staticlib-link/Makefile
-run-make/sepcomp-cci-copies/Makefile
-run-make/sepcomp-inlining/Makefile
-run-make/sepcomp-separate/Makefile
 run-make/share-generics-dylib/Makefile
 run-make/silly-file-names/Makefile
 run-make/simd-ffi/Makefile
@@ -147,9 +143,6 @@ run-make/symbol-mangling-hashed/Makefile
 run-make/symbol-visibility/Makefile
 run-make/symbols-include-type-name/Makefile
 run-make/sysroot-crates-are-unstable/Makefile
-run-make/target-cpu-native/Makefile
-run-make/target-specs/Makefile
-run-make/target-without-atomic-cas/Makefile
 run-make/test-benches/Makefile
 run-make/thumb-none-cortex-m/Makefile
 run-make/thumb-none-qemu/Makefile
diff --git a/tests/run-make/intrinsic-unreachable/Makefile b/tests/run-make/intrinsic-unreachable/Makefile
deleted file mode 100644
index ff9cc57098c..00000000000
--- a/tests/run-make/intrinsic-unreachable/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-# needs-asm-support
-# ignore-windows-msvc
-#
-# Because of Windows exception handling, the code is not necessarily any shorter.
-# https://github.com/llvm-mirror/llvm/commit/64b2297786f7fd6f5fa24cdd4db0298fbf211466
-
-all:
-	$(RUSTC) -O --emit asm exit-ret.rs
-	$(RUSTC) -O --emit asm exit-unreachable.rs
-	test `wc -l < $(TMPDIR)/exit-unreachable.s` -lt `wc -l < $(TMPDIR)/exit-ret.s`
diff --git a/tests/run-make/intrinsic-unreachable/rmake.rs b/tests/run-make/intrinsic-unreachable/rmake.rs
new file mode 100644
index 00000000000..7e78c8288b8
--- /dev/null
+++ b/tests/run-make/intrinsic-unreachable/rmake.rs
@@ -0,0 +1,20 @@
+// intrinsics::unreachable tells the compiler that a certain point in the code
+// is not reachable by any means, which enables some useful optimizations.
+// In this test, exit-unreachable contains this instruction and exit-ret does not,
+// which means the emitted artifacts should be shorter in length.
+// See https://github.com/rust-lang/rust/pull/16970
+
+//@ needs-asm-support
+//@ ignore-windows
+// Reason: Because of Windows exception handling, the code is not necessarily any shorter.
+
+use run_make_support::{fs_wrapper, rustc};
+
+fn main() {
+    rustc().opt().emit("asm").input("exit-ret.rs").run();
+    rustc().opt().emit("asm").input("exit-unreachable.rs").run();
+    assert!(
+        fs_wrapper::read_to_string("exit-unreachable.s").lines().count()
+            < fs_wrapper::read_to_string("exit-ret.s").lines().count()
+    );
+}
diff --git a/tests/run-make/llvm-ident/rmake.rs b/tests/run-make/llvm-ident/rmake.rs
index 6934a4b36d0..9699d0579f6 100644
--- a/tests/run-make/llvm-ident/rmake.rs
+++ b/tests/run-make/llvm-ident/rmake.rs
@@ -2,9 +2,9 @@
 //@ ignore-cross-compile
 
 use run_make_support::llvm::llvm_bin_dir;
-use run_make_support::{cmd, env_var, llvm_filecheck, read_dir, rustc, source_root};
-
-use std::ffi::OsStr;
+use run_make_support::{
+    cmd, env_var, has_extension, llvm_filecheck, rustc, shallow_find_files, source_root,
+};
 
 fn main() {
     // `-Ccodegen-units=16 -Copt-level=2` is used here to trigger thin LTO
@@ -22,20 +22,14 @@ fn main() {
 
     // `llvm-dis` is used here since `--emit=llvm-ir` does not emit LLVM IR
     // for temporary outputs.
-    let mut files = Vec::new();
-    read_dir(".", |path| {
-        if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("bc")) {
-            files.push(path.to_path_buf());
-        }
-    });
+    let files = shallow_find_files(".", |path| has_extension(path, "bc"));
     cmd(llvm_bin_dir().join("llvm-dis")).args(files).run();
 
     // Check LLVM IR files (including temporary outputs) have `!llvm.ident`
     // named metadata, reusing the related codegen test.
     let llvm_ident_path = source_root().join("tests/codegen/llvm-ident.rs");
-    read_dir(".", |path| {
-        if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("ll")) {
-            llvm_filecheck().input_file(path).arg(&llvm_ident_path).run();
-        }
-    });
+    let files = shallow_find_files(".", |path| has_extension(path, "ll"));
+    for file in files {
+        llvm_filecheck().input_file(file).arg(&llvm_ident_path).run();
+    }
 }
diff --git a/tests/run-make/sepcomp-cci-copies/Makefile b/tests/run-make/sepcomp-cci-copies/Makefile
deleted file mode 100644
index df289d0b0b1..00000000000
--- a/tests/run-make/sepcomp-cci-copies/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-# Check that cross-crate inlined items are inlined in all compilation units
-# that refer to them, and not in any other compilation units.
-# Note that we have to pass `-C codegen-units=6` because up to two CGUs may be
-# created for each source module (see `rustc_const_eval::monomorphize::partitioning`).
-
-all:
-	$(RUSTC) cci_lib.rs
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=6 \
-		-Z inline-in-all-cgus
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*cci_fn)" -eq "2" ]
diff --git a/tests/run-make/sepcomp-cci-copies/rmake.rs b/tests/run-make/sepcomp-cci-copies/rmake.rs
new file mode 100644
index 00000000000..612a73977fe
--- /dev/null
+++ b/tests/run-make/sepcomp-cci-copies/rmake.rs
@@ -0,0 +1,17 @@
+// Check that cross-crate inlined items are inlined in all compilation units
+// that refer to them, and not in any other compilation units.
+// Note that we have to pass `-C codegen-units=6` because up to two CGUs may be
+// created for each source module (see `rustc_const_eval::monomorphize::partitioning`).
+// See https://github.com/rust-lang/rust/pull/16367
+
+use run_make_support::{
+    count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
+    shallow_find_files,
+};
+
+fn main() {
+    rustc().input("cci_lib.rs").run();
+    rustc().input("foo.rs").emit("llvm-ir").codegen_units(6).arg("-Zinline-in-all-cgus").run();
+    let re = regex::Regex::new(r#"define\ .*cci_fn"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2);
+}
diff --git a/tests/run-make/sepcomp-inlining/Makefile b/tests/run-make/sepcomp-inlining/Makefile
deleted file mode 100644
index 327aeb75e5e..00000000000
--- a/tests/run-make/sepcomp-inlining/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-include ../tools.mk
-
-# Test that #[inline] functions still get inlined across compilation unit
-# boundaries. Compilation should produce three IR files, but only the two
-# compilation units that have a usage of the #[inline] function should
-# contain a definition. Also, the non-#[inline] function should be defined
-# in only one compilation unit.
-
-all:
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 \
-		-Z inline-in-all-cgus
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ i32\ .*inlined)" -eq "0" ]
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ]
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ]
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ]
diff --git a/tests/run-make/sepcomp-inlining/rmake.rs b/tests/run-make/sepcomp-inlining/rmake.rs
new file mode 100644
index 00000000000..de7551b9a51
--- /dev/null
+++ b/tests/run-make/sepcomp-inlining/rmake.rs
@@ -0,0 +1,23 @@
+// Test that #[inline] functions still get inlined across compilation unit
+// boundaries. Compilation should produce three IR files, but only the two
+// compilation units that have a usage of the #[inline] function should
+// contain a definition. Also, the non-#[inline] function should be defined
+// in only one compilation unit.
+// See https://github.com/rust-lang/rust/pull/16367
+
+use run_make_support::{
+    count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
+    shallow_find_files,
+};
+
+fn main() {
+    rustc().input("foo.rs").emit("llvm-ir").codegen_units(3).arg("-Zinline-in-all-cgus").run();
+    let re = regex::Regex::new(r#"define\ i32\ .*inlined"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 0);
+    let re = regex::Regex::new(r#"define\ internal\ .*inlined"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2);
+    let re = regex::Regex::new(r#"define\ hidden\ i32\ .*normal"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 1);
+    let re = regex::Regex::new(r#"declare\ hidden\ i32\ .*normal"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2);
+}
diff --git a/tests/run-make/sepcomp-separate/Makefile b/tests/run-make/sepcomp-separate/Makefile
deleted file mode 100644
index 62cf54a88fb..00000000000
--- a/tests/run-make/sepcomp-separate/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-include ../tools.mk
-
-# Test that separate compilation actually puts code into separate compilation
-# units.  `foo.rs` defines `magic_fn` in three different modules, which should
-# wind up in three different compilation units.
-
-all:
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*magic_fn)" -eq "3" ]
diff --git a/tests/run-make/sepcomp-separate/rmake.rs b/tests/run-make/sepcomp-separate/rmake.rs
new file mode 100644
index 00000000000..6f1d22424b5
--- /dev/null
+++ b/tests/run-make/sepcomp-separate/rmake.rs
@@ -0,0 +1,15 @@
+// Test that separate compilation actually puts code into separate compilation
+// units.  `foo.rs` defines `magic_fn` in three different modules, which should
+// wind up in three different compilation units.
+// See https://github.com/rust-lang/rust/pull/16367
+
+use run_make_support::{
+    count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
+    shallow_find_files,
+};
+
+fn main() {
+    rustc().input("foo.rs").emit("llvm-ir").codegen_units(3).run();
+    let re = regex::Regex::new(r#"define\ .*magic_fn"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 3);
+}
diff --git a/tests/run-make/target-cpu-native/Makefile b/tests/run-make/target-cpu-native/Makefile
deleted file mode 100644
index eb3ca1e13aa..00000000000
--- a/tests/run-make/target-cpu-native/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-include ../tools.mk
-
-# only-linux
-# only-x86_64
-#
-# I *really* don't want to deal with a cross-platform way to compare file sizes,
-# tests in `make` sort of are awful
-
-all: $(TMPDIR)/out.log
-	# Make sure no warnings about "unknown CPU `native`" were emitted
-	if [ "$$(wc -c $(TMPDIR)/out.log | cut -d' ' -f 1)" = "0" ]; then \
-	  echo no warnings generated; \
-	else \
-	  exit 1; \
-	fi
-
-
-$(TMPDIR)/out.log:
-	$(RUSTC) foo.rs -C target-cpu=native 2>&1 | tee $(TMPDIR)/out.log
-	$(call RUN,foo)
diff --git a/tests/run-make/target-cpu-native/rmake.rs b/tests/run-make/target-cpu-native/rmake.rs
new file mode 100644
index 00000000000..fd5fb6193fe
--- /dev/null
+++ b/tests/run-make/target-cpu-native/rmake.rs
@@ -0,0 +1,14 @@
+// target-cpu is a codegen flag that generates code for the processor of the host machine
+// running the compilation. This test is a sanity test that this flag does not cause any
+// warnings when used, and that binaries produced by it can also be successfully executed.
+// See https://github.com/rust-lang/rust/pull/23238
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    let out = rustc().input("foo.rs").arg("-Ctarget-cpu=native").run().stderr_utf8();
+    run("foo");
+    // There should be zero warnings emitted - the bug would cause "unknown CPU `native`"
+    // to be printed out.
+    assert!(out.is_empty());
+}
diff --git a/tests/run-make/target-specs/Makefile b/tests/run-make/target-specs/Makefile
deleted file mode 100644
index 161b6602185..00000000000
--- a/tests/run-make/target-specs/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-all:
-	$(RUSTC) foo.rs --target=my-awesome-platform.json --crate-type=lib --emit=asm
-	$(CGREP) -v morestack < $(TMPDIR)/foo.s
-	$(RUSTC) foo.rs --target=my-invalid-platform.json 2>&1 | $(CGREP) "Error loading target specification"
-	$(RUSTC) foo.rs --target=my-incomplete-platform.json 2>&1 | $(CGREP) 'Field llvm-target'
-	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-awesome-platform --crate-type=lib --emit=asm
-	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-x86_64-unknown-linux-gnu-platform --crate-type=lib --emit=asm
-	$(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json -
-	$(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin'
-	$(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian'
-	$(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib 2>&1 | $(CGREP) 'data-layout for target'
diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs
new file mode 100644
index 00000000000..d2b5f650838
--- /dev/null
+++ b/tests/run-make/target-specs/rmake.rs
@@ -0,0 +1,71 @@
+// Target-specific compilation in rustc used to have case-by-case peculiarities in 2014,
+// with the compiler having redundant target types and unspecific names. An overarching rework
+// in #16156 changed the way the target flag functions, and this test attempts compilation
+// with the target flag's bundle of new features to check that compilation either succeeds while
+// using them correctly, or fails with the right error message when using them improperly.
+// See https://github.com/rust-lang/rust/pull/16156
+
+use run_make_support::{diff, fs_wrapper, rustc};
+
+fn main() {
+    rustc().input("foo.rs").target("my-awesome-platform.json").crate_type("lib").emit("asm").run();
+    assert!(!fs_wrapper::read_to_string("foo.s").contains("morestack"));
+    rustc()
+        .input("foo.rs")
+        .target("my-invalid-platform.json")
+        .run_fail()
+        .assert_stderr_contains("Error loading target specification");
+    rustc()
+        .input("foo.rs")
+        .target("my-incomplete-platform.json")
+        .run_fail()
+        .assert_stderr_contains("Field llvm-target");
+    rustc()
+        .env("RUST_TARGET_PATH", ".")
+        .input("foo.rs")
+        .target("my-awesome-platform")
+        .crate_type("lib")
+        .emit("asm")
+        .run();
+    rustc()
+        .env("RUST_TARGET_PATH", ".")
+        .input("foo.rs")
+        .target("my-x86_64-unknown-linux-gnu-platform")
+        .crate_type("lib")
+        .emit("asm")
+        .run();
+    let test_platform = rustc()
+        .arg("-Zunstable-options")
+        .target("my-awesome-platform.json")
+        .print("target-spec-json")
+        .run()
+        .stdout_utf8();
+    fs_wrapper::create_file("test-platform.json");
+    fs_wrapper::write("test-platform.json", test_platform.as_bytes());
+    let test_platform_2 = rustc()
+        .arg("-Zunstable-options")
+        .target("test-platform.json")
+        .print("target-spec-json")
+        .run()
+        .stdout_utf8();
+    diff()
+        .expected_file("test-platform.json")
+        .actual_text("test-platform-2", test_platform_2)
+        .run();
+    rustc()
+        .input("foo.rs")
+        .target("definitely-not-builtin-target")
+        .run_fail()
+        .assert_stderr_contains("may not set is_builtin");
+    rustc()
+        .input("foo.rs")
+        .target("endianness-mismatch")
+        .run_fail()
+        .assert_stderr_contains(r#""data-layout" claims architecture is little-endian"#);
+    rustc()
+        .input("foo.rs")
+        .target("mismatching-data-layout")
+        .crate_type("lib")
+        .run_fail()
+        .assert_stderr_contains("data-layout for target");
+}
diff --git a/tests/run-make/target-without-atomic-cas/Makefile b/tests/run-make/target-without-atomic-cas/Makefile
deleted file mode 100644
index 451f03d66cd..00000000000
--- a/tests/run-make/target-without-atomic-cas/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../tools.mk
-
-# The target used below doesn't support atomic CAS operations. Verify that's the case
-all:
-	$(RUSTC) --print cfg --target thumbv6m-none-eabi | $(CGREP) -v 'target_has_atomic="ptr"'
diff --git a/tests/run-make/target-without-atomic-cas/rmake.rs b/tests/run-make/target-without-atomic-cas/rmake.rs
new file mode 100644
index 00000000000..c8782b6d1a5
--- /dev/null
+++ b/tests/run-make/target-without-atomic-cas/rmake.rs
@@ -0,0 +1,16 @@
+// ARM Cortex-M are a class of processors supported by the rust compiler. However,
+// they cannot support any atomic features, such as Arc. This test simply prints
+// the configuration details of one Cortex target, and checks that the compiler
+// does not falsely list atomic support.
+// See https://github.com/rust-lang/rust/pull/36874
+
+use run_make_support::rustc;
+
+// The target used below doesn't support atomic CAS operations. Verify that's the case
+fn main() {
+    rustc()
+        .print("cfg")
+        .target("thumbv6m-none-eabi")
+        .run()
+        .assert_stdout_not_contains(r#"target_has_atomic="ptr""#);
+}
diff --git a/tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs b/tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs
new file mode 100644
index 00000000000..0e2d1ef1208
--- /dev/null
+++ b/tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs
@@ -0,0 +1,27 @@
+//@ edition: 2021
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(async_closure)]
+
+use std::future::Future;
+use std::any::Any;
+
+struct Struct;
+impl Struct {
+    fn method(&self) {}
+}
+
+fn fake_async_closure<F, Fut>(_: F)
+where
+    F: Fn(Struct) -> Fut,
+    Fut: Future<Output = ()>,
+{}
+
+fn main() {
+    fake_async_closure(async |s| {
+        s.method();
+    })
+}