Auto merge of #139912 - matthiaskrgr:rollup-va0rqvk, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #139647 (Add unstable parsing of `--extern foo::bar=libbar.rlib` command line options) - #139823 (Fix some bootstrap papercuts) - #139867 (Fix some tidy paper cuts) - #139871 (Fix wrong "move keyword" suggestion for async gen block) - #139876 (Make CodeStats' type_sizes public) - #139880 (Don't compute name of associated item if it's an RPITIT) - #139884 (Update books) - #139886 (`borrowck_graphviz_*` attribute tweaks) - #139893 (Add test for issue 125668) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
78f2104e33
27 changed files with 395 additions and 74 deletions
|
@ -3376,10 +3376,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
|
||||
Ok(string) => {
|
||||
let coro_prefix = if string.starts_with("async") {
|
||||
// `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize`
|
||||
// to `u32`.
|
||||
Some(5)
|
||||
let coro_prefix = if let Some(sub) = string.strip_prefix("async") {
|
||||
let trimmed_sub = sub.trim_end();
|
||||
if trimmed_sub.ends_with("gen") {
|
||||
// `async` is 5 chars long.
|
||||
Some((trimmed_sub.len() + 5) as _)
|
||||
} else {
|
||||
// `async` is 5 chars long.
|
||||
Some(5)
|
||||
}
|
||||
} else if string.starts_with("gen") {
|
||||
// `gen` is 3 chars long
|
||||
Some(3)
|
||||
|
|
|
@ -204,8 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.iter()
|
||||
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
|
||||
.filter_map(|item| {
|
||||
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag)
|
||||
.then_some(item.name())
|
||||
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name())
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ impl RustcMirAttrs {
|
|||
})
|
||||
} else if attr.has_name(sym::borrowck_graphviz_format) {
|
||||
Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
|
||||
sym::gen_kill | sym::two_phase => Ok(s),
|
||||
sym::two_phase => Ok(s),
|
||||
_ => {
|
||||
tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
|
||||
Err(())
|
||||
|
|
|
@ -72,7 +72,7 @@ pub struct TypeSizeInfo {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct CodeStats {
|
||||
type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
|
||||
pub type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
|
||||
}
|
||||
|
||||
impl CodeStats {
|
||||
|
|
|
@ -14,6 +14,7 @@ use std::str::{self, FromStr};
|
|||
use std::sync::LazyLock;
|
||||
use std::{cmp, fmt, fs, iter};
|
||||
|
||||
use externs::{ExternOpt, split_extern_opt};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
|
||||
use rustc_errors::emitter::HumanReadableErrorType;
|
||||
|
@ -39,6 +40,7 @@ use crate::utils::CanonicalizedPath;
|
|||
use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint};
|
||||
|
||||
mod cfg;
|
||||
mod externs;
|
||||
mod native_libs;
|
||||
pub mod sigpipe;
|
||||
|
||||
|
@ -2205,44 +2207,13 @@ pub fn parse_externs(
|
|||
matches: &getopts::Matches,
|
||||
unstable_opts: &UnstableOptions,
|
||||
) -> Externs {
|
||||
fn is_ascii_ident(string: &str) -> bool {
|
||||
let mut chars = string.chars();
|
||||
if let Some(start) = chars.next()
|
||||
&& (start.is_ascii_alphabetic() || start == '_')
|
||||
{
|
||||
chars.all(|char| char.is_ascii_alphanumeric() || char == '_')
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
let is_unstable_enabled = unstable_opts.unstable_options;
|
||||
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
|
||||
for arg in matches.opt_strs("extern") {
|
||||
let (name, path) = match arg.split_once('=') {
|
||||
None => (arg, None),
|
||||
Some((name, path)) => (name.to_string(), Some(Path::new(path))),
|
||||
};
|
||||
let (options, name) = match name.split_once(':') {
|
||||
None => (None, name),
|
||||
Some((opts, name)) => (Some(opts), name.to_string()),
|
||||
};
|
||||
let ExternOpt { crate_name: name, path, options } =
|
||||
split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
|
||||
|
||||
if !is_ascii_ident(&name) {
|
||||
let mut error = early_dcx.early_struct_fatal(format!(
|
||||
"crate name `{name}` passed to `--extern` is not a valid ASCII identifier"
|
||||
));
|
||||
let adjusted_name = name.replace('-', "_");
|
||||
if is_ascii_ident(&adjusted_name) {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
error.help(format!(
|
||||
"consider replacing the dashes with underscores: `{adjusted_name}`"
|
||||
));
|
||||
}
|
||||
error.emit();
|
||||
}
|
||||
|
||||
let path = path.map(|p| CanonicalizedPath::new(p));
|
||||
let path = path.map(|p| CanonicalizedPath::new(p.as_path()));
|
||||
|
||||
let entry = externs.entry(name.to_owned());
|
||||
|
||||
|
|
79
compiler/rustc_session/src/config/externs.rs
Normal file
79
compiler/rustc_session/src/config/externs.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
//! This module contains code to help parse and manipulate `--extern` arguments.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_errors::{Diag, FatalAbort};
|
||||
|
||||
use super::UnstableOptions;
|
||||
use crate::EarlyDiagCtxt;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// Represents the pieces of an `--extern` argument.
|
||||
pub(crate) struct ExternOpt {
|
||||
pub(crate) crate_name: String,
|
||||
pub(crate) path: Option<PathBuf>,
|
||||
pub(crate) options: Option<String>,
|
||||
}
|
||||
|
||||
/// Breaks out the major components of an `--extern` argument.
|
||||
///
|
||||
/// The options field will be a string containing comma-separated options that will need further
|
||||
/// parsing and processing.
|
||||
pub(crate) fn split_extern_opt<'a>(
|
||||
early_dcx: &'a EarlyDiagCtxt,
|
||||
unstable_opts: &UnstableOptions,
|
||||
extern_opt: &str,
|
||||
) -> Result<ExternOpt, Diag<'a, FatalAbort>> {
|
||||
let (name, path) = match extern_opt.split_once('=') {
|
||||
None => (extern_opt.to_string(), None),
|
||||
Some((name, path)) => (name.to_string(), Some(PathBuf::from(path))),
|
||||
};
|
||||
let (options, crate_name) = match name.split_once(':') {
|
||||
None => (None, name),
|
||||
Some((opts, crate_name)) => {
|
||||
if unstable_opts.namespaced_crates && crate_name.starts_with(':') {
|
||||
// If the name starts with `:`, we know this was actually something like `foo::bar` and
|
||||
// not a set of options. We can just use the original name as the crate name.
|
||||
(None, name)
|
||||
} else {
|
||||
(Some(opts.to_string()), crate_name.to_string())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if !valid_crate_name(&crate_name, unstable_opts) {
|
||||
let mut error = early_dcx.early_struct_fatal(format!(
|
||||
"crate name `{crate_name}` passed to `--extern` is not a valid ASCII identifier"
|
||||
));
|
||||
let adjusted_name = crate_name.replace('-', "_");
|
||||
if is_ascii_ident(&adjusted_name) {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
error
|
||||
.help(format!("consider replacing the dashes with underscores: `{adjusted_name}`"));
|
||||
}
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
Ok(ExternOpt { crate_name, path, options })
|
||||
}
|
||||
|
||||
fn valid_crate_name(name: &str, unstable_opts: &UnstableOptions) -> bool {
|
||||
match name.split_once("::") {
|
||||
Some((a, b)) if unstable_opts.namespaced_crates => is_ascii_ident(a) && is_ascii_ident(b),
|
||||
Some(_) => false,
|
||||
None => is_ascii_ident(name),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_ascii_ident(string: &str) -> bool {
|
||||
let mut chars = string.chars();
|
||||
if let Some(start) = chars.next()
|
||||
&& (start.is_ascii_alphabetic() || start == '_')
|
||||
{
|
||||
chars.all(|char| char.is_ascii_alphanumeric() || char == '_')
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
92
compiler/rustc_session/src/config/externs/tests.rs
Normal file
92
compiler/rustc_session/src/config/externs/tests.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use super::split_extern_opt;
|
||||
use crate::EarlyDiagCtxt;
|
||||
use crate::config::UnstableOptions;
|
||||
|
||||
/// Verifies split_extern_opt handles the supported cases.
|
||||
#[test]
|
||||
fn test_split_extern_opt() {
|
||||
let early_dcx = EarlyDiagCtxt::new(<_>::default());
|
||||
let unstable_opts = &UnstableOptions::default();
|
||||
|
||||
let extern_opt =
|
||||
split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo=libbar.rlib").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo");
|
||||
assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
|
||||
assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
|
||||
|
||||
let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo");
|
||||
assert_eq!(extern_opt.path, None);
|
||||
assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
|
||||
|
||||
let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo=libbar.rlib").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo");
|
||||
assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
|
||||
assert_eq!(extern_opt.options, None);
|
||||
|
||||
let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo");
|
||||
assert_eq!(extern_opt.path, None);
|
||||
assert_eq!(extern_opt.options, None);
|
||||
}
|
||||
|
||||
/// Tests some invalid cases for split_extern_opt.
|
||||
#[test]
|
||||
fn test_split_extern_opt_invalid() {
|
||||
let early_dcx = EarlyDiagCtxt::new(<_>::default());
|
||||
let unstable_opts = &UnstableOptions::default();
|
||||
|
||||
// too many `:`s
|
||||
let result = split_extern_opt(&early_dcx, unstable_opts, "priv:noprelude:foo=libbar.rlib");
|
||||
assert!(result.is_err());
|
||||
let _ = result.map_err(|e| e.cancel());
|
||||
|
||||
// can't nest externs without the unstable flag
|
||||
let result = split_extern_opt(&early_dcx, unstable_opts, "noprelude:foo::bar=libbar.rlib");
|
||||
assert!(result.is_err());
|
||||
let _ = result.map_err(|e| e.cancel());
|
||||
}
|
||||
|
||||
/// Tests some cases for split_extern_opt with nested crates like `foo::bar`.
|
||||
#[test]
|
||||
fn test_split_extern_opt_nested() {
|
||||
let early_dcx = EarlyDiagCtxt::new(<_>::default());
|
||||
let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() };
|
||||
|
||||
let extern_opt =
|
||||
split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar=libbar.rlib").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo::bar");
|
||||
assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
|
||||
assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
|
||||
|
||||
let extern_opt =
|
||||
split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo::bar");
|
||||
assert_eq!(extern_opt.path, None);
|
||||
assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
|
||||
|
||||
let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar=libbar.rlib").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo::bar");
|
||||
assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
|
||||
assert_eq!(extern_opt.options, None);
|
||||
|
||||
let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar").unwrap();
|
||||
assert_eq!(extern_opt.crate_name, "foo::bar");
|
||||
assert_eq!(extern_opt.path, None);
|
||||
assert_eq!(extern_opt.options, None);
|
||||
}
|
||||
|
||||
/// Tests some invalid cases for split_extern_opt with nested crates like `foo::bar`.
|
||||
#[test]
|
||||
fn test_split_extern_opt_nested_invalid() {
|
||||
let early_dcx = EarlyDiagCtxt::new(<_>::default());
|
||||
let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() };
|
||||
|
||||
// crates can only be nested one deep.
|
||||
let result =
|
||||
split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar::baz=libbar.rlib");
|
||||
assert!(result.is_err());
|
||||
let _ = result.map_err(|e| e.cancel());
|
||||
}
|
|
@ -2334,6 +2334,8 @@ options! {
|
|||
"the size at which the `large_assignments` lint starts to be emitted"),
|
||||
mutable_noalias: bool = (true, parse_bool, [TRACKED],
|
||||
"emit noalias metadata for mutable references (default: yes)"),
|
||||
namespaced_crates: bool = (false, parse_bool, [TRACKED],
|
||||
"allow crates to be namespaced by other crates (default: no)"),
|
||||
next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED],
|
||||
"enable and configure the next generation trait solver used by rustc"),
|
||||
nll_facts: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
|
|
@ -1068,7 +1068,6 @@ symbols! {
|
|||
ge,
|
||||
gen_blocks,
|
||||
gen_future,
|
||||
gen_kill,
|
||||
generator_clone,
|
||||
generators,
|
||||
generic_arg_infer,
|
||||
|
|
|
@ -81,14 +81,19 @@ fn update_rustfmt_version(build: &Builder<'_>) {
|
|||
let Some((version, stamp_file)) = get_rustfmt_version(build) else {
|
||||
return;
|
||||
};
|
||||
t!(std::fs::write(stamp_file.path(), version))
|
||||
|
||||
t!(stamp_file.add_stamp(version).write());
|
||||
}
|
||||
|
||||
/// Returns the Rust files modified between the `merge-base` of HEAD and
|
||||
/// rust-lang/master and what is now on the disk. Does not include removed files.
|
||||
/// Returns the Rust files modified between the last merge commit and what is now on the disk.
|
||||
/// Does not include removed files.
|
||||
///
|
||||
/// Returns `None` if all files should be formatted.
|
||||
fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, String> {
|
||||
// In CI `get_git_modified_files` returns something different to normal environment.
|
||||
// This shouldn't be called in CI anyway.
|
||||
assert!(!build.config.is_running_on_ci);
|
||||
|
||||
if !verify_rustfmt_version(build) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
@ -103,7 +108,7 @@ struct RustfmtConfig {
|
|||
|
||||
// Prints output describing a collection of paths, with lines such as "formatted modified file
|
||||
// foo/bar/baz" or "skipped 20 untracked files".
|
||||
fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths: &[String]) {
|
||||
fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) {
|
||||
let len = paths.len();
|
||||
let adjective =
|
||||
if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() };
|
||||
|
@ -114,9 +119,6 @@ fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths:
|
|||
} else {
|
||||
println!("fmt: {verb} {len} {adjective}files");
|
||||
}
|
||||
if len > 1000 && !build.config.is_running_on_ci {
|
||||
println!("hint: if this number seems too high, try running `git fetch origin master`");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
||||
|
@ -189,7 +191,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
|||
)
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
print_paths(build, "skipped", Some("untracked"), &untracked_paths);
|
||||
print_paths("skipped", Some("untracked"), &untracked_paths);
|
||||
|
||||
for untracked_path in untracked_paths {
|
||||
// The leading `/` makes it an exact match against the
|
||||
|
@ -212,7 +214,13 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
|||
override_builder.add(&format!("/{file}")).expect(&file);
|
||||
}
|
||||
}
|
||||
Ok(None) => {}
|
||||
Ok(None) => {
|
||||
// NOTE: `Ok(None)` signifies that we need to format all files.
|
||||
// The tricky part here is that if `override_builder` isn't given any white
|
||||
// list files (i.e. files to be formatted, added without leading `!`), it
|
||||
// will instead look for *all* files. So, by doing nothing here, we are
|
||||
// actually making it so we format all files.
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("fmt warning: Something went wrong running git commands:");
|
||||
eprintln!("fmt warning: {err}");
|
||||
|
@ -318,7 +326,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
|||
});
|
||||
let mut paths = formatted_paths.into_inner().unwrap();
|
||||
paths.sort();
|
||||
print_paths(build, if check { "checked" } else { "formatted" }, adjective, &paths);
|
||||
print_paths(if check { "checked" } else { "formatted" }, adjective, &paths);
|
||||
|
||||
drop(tx);
|
||||
|
||||
|
@ -328,7 +336,10 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
|||
crate::exit!(1);
|
||||
}
|
||||
|
||||
if !check {
|
||||
update_rustfmt_version(build);
|
||||
}
|
||||
// Update `build/.rustfmt-stamp`, allowing this code to ignore files which have not been changed
|
||||
// since last merge.
|
||||
//
|
||||
// NOTE: Because of the exit above, this is only reachable if formatting / format checking
|
||||
// succeeded. So we are not commiting the version if formatting was not good.
|
||||
update_rustfmt_version(build);
|
||||
}
|
||||
|
|
|
@ -2888,6 +2888,13 @@ impl Config {
|
|||
|
||||
let absolute_path = self.src.join(relative_path);
|
||||
|
||||
// NOTE: This check is required because `jj git clone` doesn't create directories for
|
||||
// submodules, they are completely ignored. The code below assumes this directory exists,
|
||||
// so create it here.
|
||||
if !absolute_path.exists() {
|
||||
t!(fs::create_dir_all(&absolute_path));
|
||||
}
|
||||
|
||||
// NOTE: The check for the empty directory is here because when running x.py the first time,
|
||||
// the submodule won't be checked out. Check it out now so we can build it.
|
||||
if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
|
||||
|
|
|
@ -114,7 +114,9 @@ fn git_upstream_merge_base(
|
|||
Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
|
||||
}
|
||||
|
||||
/// Searches for the nearest merge commit in the repository that also exists upstream.
|
||||
/// Searches for the nearest merge commit in the repository.
|
||||
///
|
||||
/// **In CI** finds the nearest merge commit that *also exists upstream*.
|
||||
///
|
||||
/// It looks for the most recent commit made by the merge bot by matching the author's email
|
||||
/// address with the merge bot's email.
|
||||
|
@ -165,7 +167,7 @@ pub fn get_closest_merge_commit(
|
|||
Ok(output_result(&mut git)?.trim().to_owned())
|
||||
}
|
||||
|
||||
/// Returns the files that have been modified in the current branch compared to the master branch.
|
||||
/// Returns the files that have been modified in the current branch compared to the last merge.
|
||||
/// The `extensions` parameter can be used to filter the files by their extension.
|
||||
/// Does not include removed files.
|
||||
/// If `extensions` is empty, all files will be returned.
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 45f05367360f033f89235eacbbb54e8d73ce6b70
|
||||
Subproject commit d33916341d480caede1d0ae57cbeae23aab23e88
|
|
@ -1 +1 @@
|
|||
Subproject commit 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9c
|
||||
Subproject commit 467f45637b73ec6aa70fb36bc3054bb50b8967ea
|
|
@ -1 +1 @@
|
|||
Subproject commit b4448fa406a6dccde62d1e2f34f70fc51814cdcc
|
||||
Subproject commit 0c10c30cc54736c5c194ce98c50e2de84eeb6e79
|
|
@ -1 +1 @@
|
|||
Subproject commit 46435cd4eba11b66acaa42c01da5c80ad88aee4b
|
||||
Subproject commit 3340922df189bddcbaad17dc3927d51a76bcd5ed
|
|
@ -301,7 +301,8 @@ Right below you can find elaborate explainers on a selected few.
|
|||
|
||||
Some compiler options for debugging specific features yield graphviz graphs -
|
||||
e.g. the `#[rustc_mir(borrowck_graphviz_postflow="suffix.dot")]` attribute
|
||||
dumps various borrow-checker dataflow graphs.
|
||||
on a function dumps various borrow-checker dataflow graphs in conjunction with
|
||||
`-Zdump-mir-dataflow`.
|
||||
|
||||
These all produce `.dot` files. To view these files, install graphviz (e.g.
|
||||
`apt-get install graphviz`) and then run the following commands:
|
||||
|
|
|
@ -2378,12 +2378,19 @@ impl<'test> TestCx<'test> {
|
|||
// eg.
|
||||
// /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui/<test_dir>/$name.$revision.$mode/
|
||||
normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR");
|
||||
// Same as above, but with a canonicalized path.
|
||||
// This is required because some tests print canonical paths inside test build directory,
|
||||
// so if the build directory is a symlink, normalization doesn't help.
|
||||
//
|
||||
// NOTE: There are also tests which print the non-canonical name, so we need both this and
|
||||
// the above normalizations.
|
||||
normalize_path(&self.output_base_dir().canonicalize_utf8().unwrap(), "$TEST_BUILD_DIR");
|
||||
// eg. /home/user/rust/build
|
||||
normalize_path(&self.config.build_root, "$BUILD_DIR");
|
||||
|
||||
if json {
|
||||
// escaped newlines in json strings should be readable
|
||||
// in the stderr files. There's no point int being correct,
|
||||
// in the stderr files. There's no point in being correct,
|
||||
// since only humans process the stderr files.
|
||||
// Thus we just turn escaped newlines back into newlines.
|
||||
normalized = normalized.replace("\\n", "\n");
|
||||
|
|
|
@ -951,6 +951,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"pathdiff",
|
||||
"pulldown-cmark 0.10.3",
|
||||
"railroad",
|
||||
"regex",
|
||||
"semver",
|
||||
"serde_json",
|
||||
|
@ -1300,6 +1301,15 @@ version = "5.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "railroad"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ecedffc46c1b2cb04f4b80e094eae6b3f3f470a9635f1f396dd5206428f6b58"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
|
|
|
@ -682,8 +682,10 @@ pub static CRATES: &[&str] = &[
|
|||
pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool {
|
||||
!CiEnv::is_ci()
|
||||
&& submodules.iter().any(|submodule| {
|
||||
let path = root.join(submodule);
|
||||
!path.exists()
|
||||
// If the directory is empty, we can consider it as an uninitialized submodule.
|
||||
read_dir(root.join(submodule)).unwrap().next().is_none()
|
||||
|| read_dir(path).unwrap().next().is_none()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
35
tests/ui/async-await/async-gen-move-suggestion.fixed
Normal file
35
tests/ui/async-await/async-gen-move-suggestion.fixed
Normal file
|
@ -0,0 +1,35 @@
|
|||
// This is a regression test for <https://github.com/rust-lang/rust/issues/139839>.
|
||||
// It ensures that the "add `move` keyword" suggestion is valid.
|
||||
|
||||
//@ run-rustfix
|
||||
//@ edition:2024
|
||||
|
||||
#![feature(coroutines)]
|
||||
#![feature(gen_blocks)]
|
||||
#![feature(async_iterator)]
|
||||
|
||||
use std::async_iter::AsyncIterator;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn moved() -> impl AsyncIterator<Item = u32> {
|
||||
let mut x = "foo".to_string();
|
||||
|
||||
async gen move { //~ ERROR
|
||||
x.clear();
|
||||
for x in 3..6 { yield x }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn check_with_whitespace_chars() -> impl AsyncIterator<Item = u32> {
|
||||
let mut x = "foo".to_string();
|
||||
|
||||
async // Just to check that whitespace characters are correctly handled
|
||||
gen move { //~^ ERROR
|
||||
x.clear();
|
||||
for x in 3..6 { yield x }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
35
tests/ui/async-await/async-gen-move-suggestion.rs
Normal file
35
tests/ui/async-await/async-gen-move-suggestion.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// This is a regression test for <https://github.com/rust-lang/rust/issues/139839>.
|
||||
// It ensures that the "add `move` keyword" suggestion is valid.
|
||||
|
||||
//@ run-rustfix
|
||||
//@ edition:2024
|
||||
|
||||
#![feature(coroutines)]
|
||||
#![feature(gen_blocks)]
|
||||
#![feature(async_iterator)]
|
||||
|
||||
use std::async_iter::AsyncIterator;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn moved() -> impl AsyncIterator<Item = u32> {
|
||||
let mut x = "foo".to_string();
|
||||
|
||||
async gen { //~ ERROR
|
||||
x.clear();
|
||||
for x in 3..6 { yield x }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn check_with_whitespace_chars() -> impl AsyncIterator<Item = u32> {
|
||||
let mut x = "foo".to_string();
|
||||
|
||||
async // Just to check that whitespace characters are correctly handled
|
||||
gen { //~^ ERROR
|
||||
x.clear();
|
||||
for x in 3..6 { yield x }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
47
tests/ui/async-await/async-gen-move-suggestion.stderr
Normal file
47
tests/ui/async-await/async-gen-move-suggestion.stderr
Normal file
|
@ -0,0 +1,47 @@
|
|||
error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function
|
||||
--> $DIR/async-gen-move-suggestion.rs:17:5
|
||||
|
|
||||
LL | async gen {
|
||||
| ^^^^^^^^^ may outlive borrowed value `x`
|
||||
LL | x.clear();
|
||||
| - `x` is borrowed here
|
||||
|
|
||||
note: async gen block is returned here
|
||||
--> $DIR/async-gen-move-suggestion.rs:17:5
|
||||
|
|
||||
LL | / async gen {
|
||||
LL | | x.clear();
|
||||
LL | | for x in 3..6 { yield x }
|
||||
LL | | }
|
||||
| |_____^
|
||||
help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
LL | async gen move {
|
||||
| ++++
|
||||
|
||||
error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function
|
||||
--> $DIR/async-gen-move-suggestion.rs:27:5
|
||||
|
|
||||
LL | / async // Just to check that whitespace characters are correctly handled
|
||||
LL | | gen {
|
||||
| |_______^ may outlive borrowed value `x`
|
||||
LL | x.clear();
|
||||
| - `x` is borrowed here
|
||||
|
|
||||
note: async gen block is returned here
|
||||
--> $DIR/async-gen-move-suggestion.rs:27:5
|
||||
|
|
||||
LL | / async // Just to check that whitespace characters are correctly handled
|
||||
LL | | gen {
|
||||
LL | | x.clear();
|
||||
LL | | for x in 3..6 { yield x }
|
||||
LL | | }
|
||||
| |_____^
|
||||
help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
LL | gen move {
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0373`.
|
|
@ -0,0 +1,5 @@
|
|||
//@ check-pass
|
||||
|
||||
type A = [u32; const { 2 }];
|
||||
|
||||
fn main() {}
|
12
tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs
Normal file
12
tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/issues/139873>.
|
||||
|
||||
// Test that we don't try to get the (nonexistent) name of the RPITIT in `Trait::foo`
|
||||
// when emitting an error for a missing associated item `Trait::Output`.
|
||||
|
||||
trait Trait {
|
||||
fn foo() -> impl Sized;
|
||||
fn bar() -> Self::Output;
|
||||
//~^ ERROR associated type `Output` not found for `Self`
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,9 @@
|
|||
error[E0220]: associated type `Output` not found for `Self`
|
||||
--> $DIR/dont-probe-missing-item-name.rs:8:23
|
||||
|
|
||||
LL | fn bar() -> Self::Output;
|
||||
| ^^^^^^ associated type `Output` not found
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0220`.
|
|
@ -42,12 +42,3 @@ each generated output path.
|
|||
on *entry* to each block, as well as the gen- and kill-sets that
|
||||
were so-called "transfer functions" summarizing the effect of each
|
||||
basic block.
|
||||
|
||||
* (In addition to the `borrowck_graphviz_postflow` attribute-key
|
||||
noted above, there is also `borrowck_graphviz_preflow`; it has the
|
||||
same interface and generates the same set of files, but it renders
|
||||
the dataflow state after building the gen- and kill-sets but
|
||||
*before* running the dataflow analysis itself, so each entry-set is
|
||||
just the initial default state for that dataflow analysis. This is
|
||||
less useful for understanding the error message output in these
|
||||
tests.)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue