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
This commit is contained in:
bors 2024-07-08 20:38:48 +00:00
commit 35b658fb10
20 changed files with 329 additions and 124 deletions

View File

@ -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() => {}
_ => return None,
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.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,

View File

@ -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!(

View File

@ -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]

View File

@ -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

View File

@ -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`

View File

@ -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()
);
}

View File

@ -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();
}
}

View File

@ -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" ]

View File

@ -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);
}

View File

@ -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" ]

View File

@ -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);
}

View File

@ -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" ]

View File

@ -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);
}

View File

@ -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)

View File

@ -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());
}

View File

@ -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'

View File

@ -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");
}

View File

@ -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"'

View File

@ -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""#);
}

View File

@ -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();
})
}