mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-07 12:48:30 +00:00
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:
commit
35b658fb10
@ -424,9 +424,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if let Some(trait_def_id) = trait_def_id {
|
if let Some(trait_def_id) = trait_def_id {
|
||||||
let found_kind = match closure_kind {
|
let found_kind = match closure_kind {
|
||||||
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
|
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
|
||||||
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
|
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self
|
||||||
self.tcx.async_fn_trait_kind_from_def_id(trait_def_id)
|
.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,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -470,14 +471,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// for closures and async closures, respectively.
|
// for closures and async closures, respectively.
|
||||||
match closure_kind {
|
match closure_kind {
|
||||||
hir::ClosureKind::Closure
|
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)
|
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
|
||||||
if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
|
if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() =>
|
||||||
_ => return None,
|
{
|
||||||
|
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 = 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);
|
debug!(?arg_param_ty);
|
||||||
|
|
||||||
let ty::Tuple(input_tys) = *arg_param_ty.kind() else {
|
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.
|
// 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 = projection.skip_binder().term.expect_type();
|
||||||
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
|
|
||||||
debug!(?ret_param_ty);
|
debug!(?ret_param_ty);
|
||||||
|
|
||||||
let sig = projection.rebind(self.tcx.mk_fn_sig(
|
let sig = projection.rebind(self.tcx.mk_fn_sig(
|
||||||
@ -500,6 +523,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Some(ExpectedSig { cause_span, sig })
|
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(
|
fn sig_of_closure(
|
||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
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]
|
#[track_caller]
|
||||||
pub fn remove_file<P: AsRef<Path>>(path: P) {
|
pub fn remove_file<P: AsRef<Path>>(path: P) {
|
||||||
fs::remove_file(path.as_ref())
|
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]
|
#[track_caller]
|
||||||
pub fn create_file<P: AsRef<Path>>(path: P) {
|
pub fn create_file<P: AsRef<Path>>(path: P) {
|
||||||
fs::File::create(path.as_ref())
|
fs::File::create(path.as_ref())
|
||||||
.expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display()));
|
.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]
|
#[track_caller]
|
||||||
pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
|
pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
|
||||||
fs::read(path.as_ref())
|
fs::read(path.as_ref())
|
||||||
.expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display()))
|
.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]
|
#[track_caller]
|
||||||
pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
|
pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
|
||||||
fs::read_to_string(path.as_ref()).expect(&format!(
|
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]
|
#[track_caller]
|
||||||
pub fn read_dir<P: AsRef<Path>>(path: P) -> fs::ReadDir {
|
pub fn read_dir<P: AsRef<Path>>(path: P) -> fs::ReadDir {
|
||||||
fs::read_dir(path.as_ref())
|
fs::read_dir(path.as_ref())
|
||||||
.expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display()))
|
.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]
|
#[track_caller]
|
||||||
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
|
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
|
||||||
fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
|
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]
|
#[track_caller]
|
||||||
pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
|
pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
|
||||||
fs::remove_dir_all(path.as_ref()).expect(&format!(
|
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]
|
#[track_caller]
|
||||||
pub fn create_dir<P: AsRef<Path>>(path: P) {
|
pub fn create_dir<P: AsRef<Path>>(path: P) {
|
||||||
fs::create_dir(path.as_ref()).expect(&format!(
|
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]
|
#[track_caller]
|
||||||
pub fn create_dir_all<P: AsRef<Path>>(path: P) {
|
pub fn create_dir_all<P: AsRef<Path>>(path: P) {
|
||||||
fs::create_dir_all(path.as_ref()).expect(&format!(
|
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]
|
#[track_caller]
|
||||||
pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata {
|
pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata {
|
||||||
fs::metadata(path.as_ref()).expect(&format!(
|
fs::metadata(path.as_ref()).expect(&format!(
|
||||||
|
@ -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()))
|
.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
|
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
|
||||||
/// available on the platform!
|
/// available on the platform!
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -47,7 +47,6 @@ run-make/foreign-rust-exceptions/Makefile
|
|||||||
run-make/incr-add-rust-src-component/Makefile
|
run-make/incr-add-rust-src-component/Makefile
|
||||||
run-make/incr-foreign-head-span/Makefile
|
run-make/incr-foreign-head-span/Makefile
|
||||||
run-make/interdependent-c-libraries/Makefile
|
run-make/interdependent-c-libraries/Makefile
|
||||||
run-make/intrinsic-unreachable/Makefile
|
|
||||||
run-make/issue-107094/Makefile
|
run-make/issue-107094/Makefile
|
||||||
run-make/issue-109934-lto-debuginfo/Makefile
|
run-make/issue-109934-lto-debuginfo/Makefile
|
||||||
run-make/issue-14698/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-cdylib-link/Makefile
|
||||||
run-make/sanitizer-dylib-link/Makefile
|
run-make/sanitizer-dylib-link/Makefile
|
||||||
run-make/sanitizer-staticlib-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/share-generics-dylib/Makefile
|
||||||
run-make/silly-file-names/Makefile
|
run-make/silly-file-names/Makefile
|
||||||
run-make/simd-ffi/Makefile
|
run-make/simd-ffi/Makefile
|
||||||
@ -147,9 +143,6 @@ run-make/symbol-mangling-hashed/Makefile
|
|||||||
run-make/symbol-visibility/Makefile
|
run-make/symbol-visibility/Makefile
|
||||||
run-make/symbols-include-type-name/Makefile
|
run-make/symbols-include-type-name/Makefile
|
||||||
run-make/sysroot-crates-are-unstable/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/test-benches/Makefile
|
||||||
run-make/thumb-none-cortex-m/Makefile
|
run-make/thumb-none-cortex-m/Makefile
|
||||||
run-make/thumb-none-qemu/Makefile
|
run-make/thumb-none-qemu/Makefile
|
||||||
|
@ -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`
|
|
20
tests/run-make/intrinsic-unreachable/rmake.rs
Normal file
20
tests/run-make/intrinsic-unreachable/rmake.rs
Normal 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()
|
||||||
|
);
|
||||||
|
}
|
@ -2,9 +2,9 @@
|
|||||||
//@ ignore-cross-compile
|
//@ ignore-cross-compile
|
||||||
|
|
||||||
use run_make_support::llvm::llvm_bin_dir;
|
use run_make_support::llvm::llvm_bin_dir;
|
||||||
use run_make_support::{cmd, env_var, llvm_filecheck, read_dir, rustc, source_root};
|
use run_make_support::{
|
||||||
|
cmd, env_var, has_extension, llvm_filecheck, rustc, shallow_find_files, source_root,
|
||||||
use std::ffi::OsStr;
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// `-Ccodegen-units=16 -Copt-level=2` is used here to trigger thin LTO
|
// `-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
|
// `llvm-dis` is used here since `--emit=llvm-ir` does not emit LLVM IR
|
||||||
// for temporary outputs.
|
// for temporary outputs.
|
||||||
let mut files = Vec::new();
|
let files = shallow_find_files(".", |path| has_extension(path, "bc"));
|
||||||
read_dir(".", |path| {
|
|
||||||
if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("bc")) {
|
|
||||||
files.push(path.to_path_buf());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cmd(llvm_bin_dir().join("llvm-dis")).args(files).run();
|
cmd(llvm_bin_dir().join("llvm-dis")).args(files).run();
|
||||||
|
|
||||||
// Check LLVM IR files (including temporary outputs) have `!llvm.ident`
|
// Check LLVM IR files (including temporary outputs) have `!llvm.ident`
|
||||||
// named metadata, reusing the related codegen test.
|
// named metadata, reusing the related codegen test.
|
||||||
let llvm_ident_path = source_root().join("tests/codegen/llvm-ident.rs");
|
let llvm_ident_path = source_root().join("tests/codegen/llvm-ident.rs");
|
||||||
read_dir(".", |path| {
|
let files = shallow_find_files(".", |path| has_extension(path, "ll"));
|
||||||
if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("ll")) {
|
for file in files {
|
||||||
llvm_filecheck().input_file(path).arg(&llvm_ident_path).run();
|
llvm_filecheck().input_file(file).arg(&llvm_ident_path).run();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -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" ]
|
|
17
tests/run-make/sepcomp-cci-copies/rmake.rs
Normal file
17
tests/run-make/sepcomp-cci-copies/rmake.rs
Normal 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);
|
||||||
|
}
|
@ -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" ]
|
|
23
tests/run-make/sepcomp-inlining/rmake.rs
Normal file
23
tests/run-make/sepcomp-inlining/rmake.rs
Normal 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);
|
||||||
|
}
|
@ -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" ]
|
|
15
tests/run-make/sepcomp-separate/rmake.rs
Normal file
15
tests/run-make/sepcomp-separate/rmake.rs
Normal 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);
|
||||||
|
}
|
@ -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)
|
|
14
tests/run-make/target-cpu-native/rmake.rs
Normal file
14
tests/run-make/target-cpu-native/rmake.rs
Normal 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());
|
||||||
|
}
|
@ -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'
|
|
71
tests/run-make/target-specs/rmake.rs
Normal file
71
tests/run-make/target-specs/rmake.rs
Normal 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");
|
||||||
|
}
|
@ -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"'
|
|
16
tests/run-make/target-without-atomic-cas/rmake.rs
Normal file
16
tests/run-make/target-without-atomic-cas/rmake.rs
Normal 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""#);
|
||||||
|
}
|
@ -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();
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user