diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index ac7ed3e26f976..53cf121dfebcd 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` 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, + projection: ty::PolyProjectionPredicate<'tcx>, + ) -> Option> { + 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: F) + /// where + /// F: FnOnce(String, u32) -> Fut, + /// Fut: Future, + /// {} + /// ``` + /// + /// 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` bound, and if the output type is + /// an inference variable `?Fut`, we check if that is bounded by a `Future` + /// projection. + fn extract_sig_from_projection_and_future_bound( + &self, + cause_span: Option, + projection: ty::PolyProjectionPredicate<'tcx>, + ) -> Option> { + 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 8a2bfce8b4a72..0f0d6f6618ced 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>(path: P) { fs::remove_file(path.as_ref()) @@ -18,21 +18,21 @@ pub fn copy, Q: AsRef>(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>(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>(path: P) -> Vec { 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>(path: P) -> String { fs::read_to_string(path.as_ref()).expect(&format!( @@ -41,14 +41,14 @@ pub fn read_to_string>(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>(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, C: AsRef<[u8]>>(path: P, contents: C) { fs::write(path.as_ref(), contents.as_ref()).expect(&format!( @@ -57,7 +57,7 @@ pub fn write, 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>(path: P) { fs::remove_dir_all(path.as_ref()).expect(&format!( @@ -66,7 +66,7 @@ pub fn remove_dir_all>(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>(path: P) { fs::create_dir(path.as_ref()).expect(&format!( @@ -75,7 +75,7 @@ pub fn create_dir>(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>(path: P) { fs::create_dir_all(path.as_ref()).expect(&format!( @@ -84,7 +84,7 @@ pub fn create_dir_all>(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>(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 f464a109e7711..3fdf94804f16a 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, 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: ®ex::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 31cb32d349ace..e658621ab8852 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 ff9cc57098c6b..0000000000000 --- 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 0000000000000..7e78c8288b821 --- /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 6934a4b36d013..9699d0579f6ef 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 df289d0b0b1a2..0000000000000 --- 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 0000000000000..612a73977feea --- /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 327aeb75e5eda..0000000000000 --- 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 0000000000000..de7551b9a512d --- /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 62cf54a88fbe9..0000000000000 --- 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 0000000000000..6f1d22424b5b9 --- /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 eb3ca1e13aa62..0000000000000 --- 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 0000000000000..fd5fb6193fe06 --- /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 161b66021857b..0000000000000 --- 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 0000000000000..d2b5f65083808 --- /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 451f03d66cd23..0000000000000 --- 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 0000000000000..c8782b6d1a566 --- /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 0000000000000..0e2d1ef12082b --- /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) +where + F: Fn(Struct) -> Fut, + Fut: Future, +{} + +fn main() { + fake_async_closure(async |s| { + s.method(); + }) +}