about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs2
-rw-r--r--compiler/rustc_session/src/code_stats.rs2
-rw-r--r--compiler/rustc_session/src/config.rs39
-rw-r--r--compiler/rustc_session/src/config/externs.rs79
-rw-r--r--compiler/rustc_session/src/config/externs/tests.rs92
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs37
-rw-r--r--src/bootstrap/src/core/config/config.rs7
-rw-r--r--src/build_helper/src/git.rs6
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-debugging.md3
-rw-r--r--src/tools/compiletest/src/runtest.rs9
-rw-r--r--src/tools/rustbook/Cargo.lock10
-rw-r--r--src/tools/tidy/src/deps.rs4
-rw-r--r--tests/ui/async-await/async-gen-move-suggestion.fixed35
-rw-r--r--tests/ui/async-await/async-gen-move-suggestion.rs35
-rw-r--r--tests/ui/async-await/async-gen-move-suggestion.stderr47
-rw-r--r--tests/ui/consts/const-blocks/const-block-in-array-size.rs5
-rw-r--r--tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs12
-rw-r--r--tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr9
-rw-r--r--tests/ui/mir-dataflow/README.md9
27 files changed, 391 insertions, 70 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index fe6dff7ff1b..959cf9fa513 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -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)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 72f219bfeb8..3759a224ff7 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -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();
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 448fad2dc3e..c436b8c0fb0 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -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(())
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index b4597ae2515..6b18d450e9e 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -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 {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index fc05470d941..202378560ee 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -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()),
-        };
-
-        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 ExternOpt { crate_name: name, path, options } =
+            split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.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());
 
diff --git a/compiler/rustc_session/src/config/externs.rs b/compiler/rustc_session/src/config/externs.rs
new file mode 100644
index 00000000000..1420ee38bf2
--- /dev/null
+++ b/compiler/rustc_session/src/config/externs.rs
@@ -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
+    }
+}
diff --git a/compiler/rustc_session/src/config/externs/tests.rs b/compiler/rustc_session/src/config/externs/tests.rs
new file mode 100644
index 00000000000..65448869515
--- /dev/null
+++ b/compiler/rustc_session/src/config/externs/tests.rs
@@ -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());
+}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index ea3a1f8bd8c..1b0794f79d3 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -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],
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d1f3eb16e4e..2af567f2ec5 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1068,7 +1068,6 @@ symbols! {
         ge,
         gen_blocks,
         gen_future,
-        gen_kill,
         generator_clone,
         generators,
         generic_arg_infer,
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index b1a97bde97b..9da8b27a917 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -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);
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 25ec64f90b5..2266e61bf60 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -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()
diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs
index 693e0fc8f46..f5347c30824 100644
--- a/src/build_helper/src/git.rs
+++ b/src/build_helper/src/git.rs
@@ -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.
diff --git a/src/doc/book b/src/doc/book
-Subproject 45f05367360f033f89235eacbbb54e8d73ce6b7
+Subproject d33916341d480caede1d0ae57cbeae23aab23e8
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9
+Subproject 467f45637b73ec6aa70fb36bc3054bb50b8967e
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject b4448fa406a6dccde62d1e2f34f70fc51814cdc
+Subproject 0c10c30cc54736c5c194ce98c50e2de84eeb6e7
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 46435cd4eba11b66acaa42c01da5c80ad88aee4
+Subproject 3340922df189bddcbaad17dc3927d51a76bcd5e
diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md
index 47f39762022..102e2020779 100644
--- a/src/doc/rustc-dev-guide/src/compiler-debugging.md
+++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md
@@ -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:
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 24fc2ddb741..eb298060b2e 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -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");
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index e0939afc09b..c14372dd6ae 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -951,6 +951,7 @@ dependencies = [
  "once_cell",
  "pathdiff",
  "pulldown-cmark 0.10.3",
+ "railroad",
  "regex",
  "semver",
  "serde_json",
@@ -1301,6 +1302,15 @@ 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"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 88c2a02798a..46e55859a57 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -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()
         })
 }
 
diff --git a/tests/ui/async-await/async-gen-move-suggestion.fixed b/tests/ui/async-await/async-gen-move-suggestion.fixed
new file mode 100644
index 00000000000..d8020765528
--- /dev/null
+++ b/tests/ui/async-await/async-gen-move-suggestion.fixed
@@ -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() {
+}
diff --git a/tests/ui/async-await/async-gen-move-suggestion.rs b/tests/ui/async-await/async-gen-move-suggestion.rs
new file mode 100644
index 00000000000..825fb0fd189
--- /dev/null
+++ b/tests/ui/async-await/async-gen-move-suggestion.rs
@@ -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() {
+}
diff --git a/tests/ui/async-await/async-gen-move-suggestion.stderr b/tests/ui/async-await/async-gen-move-suggestion.stderr
new file mode 100644
index 00000000000..b8cdb8be7a4
--- /dev/null
+++ b/tests/ui/async-await/async-gen-move-suggestion.stderr
@@ -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`.
diff --git a/tests/ui/consts/const-blocks/const-block-in-array-size.rs b/tests/ui/consts/const-blocks/const-block-in-array-size.rs
new file mode 100644
index 00000000000..ecab2432286
--- /dev/null
+++ b/tests/ui/consts/const-blocks/const-block-in-array-size.rs
@@ -0,0 +1,5 @@
+//@ check-pass
+
+type A = [u32; const { 2 }];
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs
new file mode 100644
index 00000000000..450f41e209d
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs
@@ -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() {}
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr
new file mode 100644
index 00000000000..74e15785af1
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr
@@ -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`.
diff --git a/tests/ui/mir-dataflow/README.md b/tests/ui/mir-dataflow/README.md
index a3ab14b23c7..886020226d0 100644
--- a/tests/ui/mir-dataflow/README.md
+++ b/tests/ui/mir-dataflow/README.md
@@ -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.)