Skip to content

Commit

Permalink
Auto merge of rust-lang#127489 - GuillaumeGomez:rollup-rhqfeom, r=Gui…
Browse files Browse the repository at this point in the history
…llaumeGomez

Rollup of 4 pull requests

Successful merges:

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

Failed merges:

 - rust-lang#127357 (Remove `StructuredDiag`)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jul 8, 2024
2 parents 32e6926 + 72199b2 commit 35b658f
Show file tree
Hide file tree
Showing 20 changed files with 329 additions and 124 deletions.
102 changes: 94 additions & 8 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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 {
Expand All @@ -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(
Expand All @@ -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,
Expand Down
20 changes: 10 additions & 10 deletions src/tools/run-make-support/src/fs_wrapper.rs
Original file line number Diff line number Diff line change
@@ -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())
Expand All @@ -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!(
Expand All @@ -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!(
Expand All @@ -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!(
Expand All @@ -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!(
Expand All @@ -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!(
Expand All @@ -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!(
Expand Down
14 changes: 14 additions & 0 deletions src/tools/run-make-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
7 changes: 0 additions & 7 deletions src/tools/tidy/src/allowed_run_make_makefiles.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
12 changes: 0 additions & 12 deletions tests/run-make/intrinsic-unreachable/Makefile

This file was deleted.

20 changes: 20 additions & 0 deletions tests/run-make/intrinsic-unreachable/rmake.rs
Original file line number Diff line number Diff line change
@@ -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()
);
}
22 changes: 8 additions & 14 deletions tests/run-make/llvm-ident/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();
}
}
12 changes: 0 additions & 12 deletions tests/run-make/sepcomp-cci-copies/Makefile

This file was deleted.

17 changes: 17 additions & 0 deletions tests/run-make/sepcomp-cci-copies/rmake.rs
Original file line number Diff line number Diff line change
@@ -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);
}
15 changes: 0 additions & 15 deletions tests/run-make/sepcomp-inlining/Makefile

This file was deleted.

Loading

0 comments on commit 35b658f

Please sign in to comment.