From b2a7713ae384789733f0919886cd5ea890b0cf20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 21 Aug 2024 03:17:47 +0000
Subject: [PATCH 1/6] Emit specific message for `time<0.3.35` inference failure

```
error[E0282]: type annotations needed for `Box<_>`
  --> ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/time-0.3.34/src/format_description/parse/mod.rs:83:9
   |
83 |     let items = format_items
   |         ^^^^^
...
86 |     Ok(items.into())
   |              ---- type must be known at this point
   |
   = note: this is an inference error on crate `time` caused by a change in Rust 1.80.0; update `time` to version `>=0.3.35`
```

Partially address #127343.

(cherry picked from commit b013a3ddf0060b62ee8050e241f80d024c48cc59)
---
 compiler/rustc_infer/messages.ftl             |  2 +
 compiler/rustc_infer/src/errors/mod.rs        |  2 +
 .../rustc_infer/src/infer/need_type_info.rs   | 46 ++++++++++++++++++-
 compiler/rustc_infer/src/lib.rs               |  1 +
 compiler/rustc_span/src/symbol.rs             |  1 +
 ...d-time-version-format_description-parse.rs |  8 ++++
 ...me-version-format_description-parse.stderr | 11 +++++
 7 files changed, 69 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/inference/detect-old-time-version-format_description-parse.rs
 create mode 100644 tests/ui/inference/detect-old-time-version-format_description-parse.stderr

diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index c279195a7e99c..b40c353f0775b 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -388,6 +388,8 @@ infer_type_annotations_needed = {$source_kind ->
 }
     .label = type must be known at this point
 
+infer_type_annotations_needed_error_time = this is an inference error on crate `time` caused by an API change in Rust 1.80.0; update `time` to version `>=0.3.35` by calling `cargo update`
+
 infer_types_declared_different = these two types are declared with different lifetimes...
 
 infer_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 2ce712e0bff58..10b6ddeb1779f 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -54,6 +54,8 @@ pub struct AnnotationRequired<'a> {
     #[note(infer_full_type_written)]
     pub was_written: Option<()>,
     pub path: PathBuf,
+    #[note(infer_type_annotations_needed_error_time)]
+    pub time_version: bool,
 }
 
 // Copy of `AnnotationRequired` for E0283
diff --git a/compiler/rustc_infer/src/infer/need_type_info.rs b/compiler/rustc_infer/src/infer/need_type_info.rs
index 4f3dcd9043fd0..4ac5b521926d3 100644
--- a/compiler/rustc_infer/src/infer/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/need_type_info.rs
@@ -8,7 +8,7 @@ use rustc_errors::{codes::*, Diag, IntoDiagArg};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
 use rustc_middle::bug;
@@ -21,7 +21,7 @@ use rustc_middle::ty::{
     TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults,
 };
 use rustc_span::symbol::{sym, Ident};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
 use std::borrow::Cow;
 use std::iter;
 use std::path::PathBuf;
@@ -409,6 +409,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 bad_label,
                 was_written: None,
                 path: Default::default(),
+                time_version: false,
             }),
             TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
@@ -604,6 +605,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
             }
         }
+
+        let time_version =
+            self.detect_old_time_crate_version(failure_span, &kind, &mut infer_subdiags);
+
         match error_code {
             TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired {
                 span,
@@ -615,6 +620,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 bad_label: None,
                 was_written: path.as_ref().map(|_| ()),
                 path: path.unwrap_or_default(),
+                time_version,
             }),
             TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
@@ -640,6 +646,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }),
         }
     }
+
+    /// Detect the inference regression on crate `time` <= 0.3.35 and emit a more targeted error.
+    /// <https://github.com/rust-lang/rust/issues/127343>
+    // FIXME: we should figure out a more generic version of doing this, ideally in cargo itself.
+    fn detect_old_time_crate_version(
+        &self,
+        span: Option<Span>,
+        kind: &InferSourceKind<'_>,
+        // We will clear the non-actionable suggestion from the error to reduce noise.
+        infer_subdiags: &mut Vec<SourceKindSubdiag<'_>>,
+    ) -> bool {
+        // FIXME(#129461): We are time-boxing this code in the compiler. It'll start failing
+        // compilation once we promote 1.89 to beta, which will happen in 9 months from now.
+        #[cfg(not(version("1.89")))]
+        const fn version_check() {}
+        #[cfg(version("1.89"))]
+        const fn version_check() {
+            panic!("remove this check as presumably the ecosystem has moved from needing it");
+        }
+        const { version_check() };
+        // Only relevant when building the `time` crate.
+        if self.infcx.tcx.crate_name(LOCAL_CRATE) == sym::time
+            && let Some(span) = span
+            && let InferSourceKind::LetBinding { pattern_name, .. } = kind
+            && let Some(name) = pattern_name
+            && name.as_str() == "items"
+            && let FileName::Real(file) = self.infcx.tcx.sess.source_map().span_to_filename(span)
+        {
+            let path = file.local_path_if_available().to_string_lossy();
+            if path.contains("format_description") && path.contains("parse") {
+                infer_subdiags.clear();
+                return true;
+            }
+        }
+        false
+    }
 }
 
 #[derive(Debug)]
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 02ebf933f5329..fc47f5c11b7a9 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -19,6 +19,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(box_patterns)]
+#![feature(cfg_version)]
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b64efadb2619e..99d80eda37473 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1883,6 +1883,7 @@ symbols! {
         three_way_compare,
         thumb2,
         thumb_mode: "thumb-mode",
+        time,
         tmm_reg,
         to_owned_method,
         to_string,
diff --git a/tests/ui/inference/detect-old-time-version-format_description-parse.rs b/tests/ui/inference/detect-old-time-version-format_description-parse.rs
new file mode 100644
index 0000000000000..453a795e7686b
--- /dev/null
+++ b/tests/ui/inference/detect-old-time-version-format_description-parse.rs
@@ -0,0 +1,8 @@
+#![crate_name = "time"]
+
+fn main() {
+    let items = Box::new(vec![]); //~ ERROR E0282
+    //~^ NOTE type must be known at this point
+    //~| NOTE this is an inference error on crate `time` caused by an API change in Rust 1.80.0; update `time` to version `>=0.3.35`
+    items.into();
+}
diff --git a/tests/ui/inference/detect-old-time-version-format_description-parse.stderr b/tests/ui/inference/detect-old-time-version-format_description-parse.stderr
new file mode 100644
index 0000000000000..2949a5dcfec9c
--- /dev/null
+++ b/tests/ui/inference/detect-old-time-version-format_description-parse.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed for `Box<Vec<_>>`
+  --> $DIR/detect-old-time-version-format_description-parse.rs:4:9
+   |
+LL |     let items = Box::new(vec![]);
+   |         ^^^^^   ---------------- type must be known at this point
+   |
+   = note: this is an inference error on crate `time` caused by an API change in Rust 1.80.0; update `time` to version `>=0.3.35` by calling `cargo update`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0282`.

From 1953a13a9e81e34eb0335d8d2ae8a53a7b7d0b11 Mon Sep 17 00:00:00 2001
From: Ben Kimock <kimockb@gmail.com>
Date: Wed, 28 Aug 2024 19:36:46 -0400
Subject: [PATCH 2/6] Use a reduced recursion limit in the MIR inliner's cycle
 breaker

(cherry picked from commit 950437a035aa81cf2af3d8aebdf8d9b294c54395)
---
 compiler/rustc_mir_transform/src/inline/cycle.rs | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index d4477563e3adb..9ef6b20e77a69 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -137,6 +137,14 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
         }
         false
     }
+    // FIXME(-Znext-solver): Remove this hack when trait solver overflow can return an error.
+    // In code like that pointed out in #128887, the type complexity we ask the solver to deal with
+    // grows as we recurse into the call graph. If we use the same recursion limit here and in the
+    // solver, the solver hits the limit first and emits a fatal error. But if we use a reduced
+    // limit, we will hit the limit first and give up on looking for inlining. And in any case,
+    // the default recursion limits are quite generous for us. If we need to recurse 64 times
+    // into the call graph, we're probably not going to find any useful MIR inlining.
+    let recursion_limit = tcx.recursion_limit() / 2;
     process(
         tcx,
         param_env,
@@ -145,7 +153,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
         &mut Vec::new(),
         &mut FxHashSet::default(),
         &mut FxHashMap::default(),
-        tcx.recursion_limit(),
+        recursion_limit,
     )
 }
 

From cfb20bc74ebc828e7dd22bf6cf83aa654daa2732 Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Thu, 8 Aug 2024 11:36:48 -0700
Subject: [PATCH 3/6] rustdoc: do not run doctests with invalid langstrings

(cherry picked from commit 7c4150fce0510218304b726174029fbb2c33ee03)
---
 src/librustdoc/html/markdown.rs               | 20 +++++++++++++++----
 src/librustdoc/html/markdown/tests.rs         |  6 +++---
 ...octest-no-run-invalid-langstring-124577.rs | 11 ++++++++++
 3 files changed, 30 insertions(+), 7 deletions(-)
 create mode 100644 tests/rustdoc/doctest/doctest-no-run-invalid-langstring-124577.rs

diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index a7f0df5afa98f..e9fc3a3ffcee8 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -925,6 +925,7 @@ pub(crate) struct TagIterator<'a, 'tcx> {
     data: &'a str,
     is_in_attribute_block: bool,
     extra: Option<&'a ExtraInfo<'tcx>>,
+    is_error: bool,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -951,13 +952,20 @@ struct Indices {
 
 impl<'a, 'tcx> TagIterator<'a, 'tcx> {
     pub(crate) fn new(data: &'a str, extra: Option<&'a ExtraInfo<'tcx>>) -> Self {
-        Self { inner: data.char_indices().peekable(), data, is_in_attribute_block: false, extra }
+        Self {
+            inner: data.char_indices().peekable(),
+            data,
+            is_in_attribute_block: false,
+            extra,
+            is_error: false,
+        }
     }
 
-    fn emit_error(&self, err: impl Into<DiagMessage>) {
+    fn emit_error(&mut self, err: impl Into<DiagMessage>) {
         if let Some(extra) = self.extra {
             extra.error_invalid_codeblock_attr(err);
         }
+        self.is_error = true;
     }
 
     fn skip_separators(&mut self) -> Option<usize> {
@@ -1155,6 +1163,9 @@ impl<'a, 'tcx> Iterator for TagIterator<'a, 'tcx> {
     type Item = LangStringToken<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
+        if self.is_error {
+            return None;
+        }
         let Some(start) = self.skip_separators() else {
             if self.is_in_attribute_block {
                 self.emit_error("unclosed attribute block (`{}`): missing `}` at the end");
@@ -1343,14 +1354,15 @@ impl LangString {
             }
         };
 
-        call(&mut TagIterator::new(string, extra));
+        let mut tag_iter = TagIterator::new(string, extra);
+        call(&mut tag_iter);
 
         // ignore-foo overrides ignore
         if !ignores.is_empty() {
             data.ignore = Ignore::Some(ignores);
         }
 
-        data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags);
+        data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags) && !tag_iter.is_error;
 
         data
     }
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index fb74c079c9a4e..23da2f0cc7fb4 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -61,7 +61,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: "{rust}".into(), rust: true, ..Default::default() });
+    t(LangString { original: "{rust}".into(), rust: false, ..Default::default() });
     t(LangString {
         original: "{.rust}".into(),
         rust: true,
@@ -233,7 +233,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: "{class=first=second}".into(), rust: true, ..Default::default() });
+    t(LangString { original: "{class=first=second}".into(), rust: false, ..Default::default() });
     // error
     t(LangString {
         original: "{class=first.second}".into(),
@@ -261,7 +261,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: r#"{class=f"irst"}"#.into(), rust: true, ..Default::default() });
+    t(LangString { original: r#"{class=f"irst"}"#.into(), rust: false, ..Default::default() });
 }
 
 #[test]
diff --git a/tests/rustdoc/doctest/doctest-no-run-invalid-langstring-124577.rs b/tests/rustdoc/doctest/doctest-no-run-invalid-langstring-124577.rs
new file mode 100644
index 0000000000000..b3e993e8ee939
--- /dev/null
+++ b/tests/rustdoc/doctest/doctest-no-run-invalid-langstring-124577.rs
@@ -0,0 +1,11 @@
+//@ compile-flags:--test
+#![allow(rustdoc::invalid_codeblock_attributes)]
+
+// https://github.com/rust-lang/rust/pull/124577#issuecomment-2276034737
+
+// Test that invalid langstrings don't get run.
+
+/// ```{rust,ignore}
+/// panic!();
+/// ```
+pub struct Foo;

From 6f593122b26e574e833c5876ea922c52d5c695cb Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Fri, 9 Aug 2024 07:57:46 -0700
Subject: [PATCH 4/6] rustdoc: move invalid langstring test to UI

(cherry picked from commit 1d19c2c009529fff08a95cbe548bcb1a6e02651c)
---
 .../doctest/doctest-no-run-invalid-langstring-124577.rs      | 1 +
 .../doctest/doctest-no-run-invalid-langstring-124577.stdout  | 5 +++++
 2 files changed, 6 insertions(+)
 rename tests/{rustdoc => rustdoc-ui}/doctest/doctest-no-run-invalid-langstring-124577.rs (94%)
 create mode 100644 tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout

diff --git a/tests/rustdoc/doctest/doctest-no-run-invalid-langstring-124577.rs b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
similarity index 94%
rename from tests/rustdoc/doctest/doctest-no-run-invalid-langstring-124577.rs
rename to tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
index b3e993e8ee939..571bc94e30f98 100644
--- a/tests/rustdoc/doctest/doctest-no-run-invalid-langstring-124577.rs
+++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
@@ -1,4 +1,5 @@
 //@ compile-flags:--test
+//@ check-pass
 #![allow(rustdoc::invalid_codeblock_attributes)]
 
 // https://github.com/rust-lang/rust/pull/124577#issuecomment-2276034737
diff --git a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout
new file mode 100644
index 0000000000000..e5c27bebbdb23
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout
@@ -0,0 +1,5 @@
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+

From 361a050c0029583b9edb6ddbf53a62643500afc3 Mon Sep 17 00:00:00 2001
From: Jubilee Young <workingjubilee@gmail.com>
Date: Fri, 30 Aug 2024 18:03:04 -0700
Subject: [PATCH 5/6] ci: Use mv instead of cp in upload step

---
 src/ci/scripts/upload-artifacts.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/ci/scripts/upload-artifacts.sh b/src/ci/scripts/upload-artifacts.sh
index c9c85ec20b45a..587b324ce10e5 100755
--- a/src/ci/scripts/upload-artifacts.sh
+++ b/src/ci/scripts/upload-artifacts.sh
@@ -19,18 +19,18 @@ fi
 if [[ "${DEPLOY-0}" -eq "1" ]] || [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then
     dist_dir="${build_dir}/dist"
     rm -rf "${dist_dir}/doc"
-    cp -r "${dist_dir}"/* "${upload_dir}"
+    mv "${dist_dir}"/* "${upload_dir}"
 fi
 
 # CPU usage statistics.
-cp build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv"
+mv build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv"
 
 # Build metrics generated by x.py.
-cp "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json"
+mv "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json"
 
 # Toolstate data.
 if [[ -n "${DEPLOY_TOOLSTATES_JSON+x}" ]]; then
-    cp /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}"
+    mv /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}"
 fi
 
 echo "Files that will be uploaded:"

From a4461dfb58cdcdac0480562dfe4d9e6391e5f517 Mon Sep 17 00:00:00 2001
From: Jubilee Young <workingjubilee@gmail.com>
Date: Fri, 30 Aug 2024 18:02:03 -0700
Subject: [PATCH 6/6] ci: Try to remove unused Xcode dirs

---
 src/ci/scripts/select-xcode.sh | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh
index 569c4a4136d97..d635d4384727f 100755
--- a/src/ci/scripts/select-xcode.sh
+++ b/src/ci/scripts/select-xcode.sh
@@ -1,5 +1,6 @@
 #!/bin/bash
 # This script selects the Xcode instance to use.
+# It also tries to do some cleanup in CI jobs of unused Xcodes.
 
 set -euo pipefail
 IFS=$'\n\t'
@@ -7,5 +8,21 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 if isMacOS; then
+    # This additional step is to try to remove an Xcode we aren't using because each one is HUGE
+    old_xcode="$(xcode-select --print-path)"
+    old_xcode="${old_xcode%/*}" # pop a dir
+    old_xcode="${old_xcode%/*}" # twice
+    if [[ $old_xcode =~ $SELECT_XCODE ]]; then
+        echo "xcode-select.sh's brutal hack may not be necessary?"
+        exit 1
+    elif [[ $SELECT_XCODE =~ "16" ]]; then
+        echo "Using Xcode 16? Please fix xcode-select.sh"
+        exit 1
+    fi
+    if [ $CI ]; then # just in case someone sources this on their real computer
+        sudo rm -rf "${old_xcode}"
+        xcode_16="${old_xcode%/*}/Xcode-16.0.0.app"
+        sudo rm -rf "${xcode_16}"
+    fi
     sudo xcode-select -s "${SELECT_XCODE}"
 fi