summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock26
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs72
-rw-r--r--compiler/rustc_interface/src/tests.rs12
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs10
-rw-r--r--compiler/rustc_session/src/config.rs22
-rw-r--r--compiler/rustc_session/src/options.rs24
-rw-r--r--config.example.toml10
-rw-r--r--src/bootstrap/Cargo.lock40
-rw-r--r--src/bootstrap/defaults/config.codegen.toml2
-rw-r--r--src/bootstrap/download-ci-llvm-stamp2
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs26
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs9
-rw-r--r--src/bootstrap/src/core/config/config.rs101
-rw-r--r--src/bootstrap/src/lib.rs2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/aix.md26
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/clean/utils.rs6
m---------src/tools/cargo0
-rw-r--r--src/tools/rust-installer/Cargo.toml1
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--tests/codegen/cross-crate-inlining/always-inline.rs13
-rw-r--r--tests/codegen/cross-crate-inlining/auxiliary/always.rs20
-rw-r--r--tests/codegen/cross-crate-inlining/auxiliary/leaf.rs20
-rw-r--r--tests/codegen/cross-crate-inlining/auxiliary/never.rs20
-rw-r--r--tests/codegen/cross-crate-inlining/leaf-inlining.rs20
-rw-r--r--tests/codegen/cross-crate-inlining/never-inline.rs13
-rw-r--r--tests/rustdoc/const-effect-param.rs2
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs16
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/const-fn.rs5
-rw-r--r--tests/rustdoc/inline_cross/const-effect-param.rs29
-rw-r--r--tests/rustdoc/inline_cross/const-fn.rs10
-rw-r--r--tests/ui/macros/stringify.rs31
35 files changed, 443 insertions, 156 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 09e189fcac0..adaac69af57 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1281,26 +1281,15 @@ checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
 
 [[package]]
 name = "errno"
-version = "0.3.1"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
 dependencies = [
- "errno-dragonfly",
  "libc",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
 name = "error_index_generator"
 version = "0.0.0"
 dependencies = [
@@ -2055,7 +2044,6 @@ dependencies = [
  "anyhow",
  "clap",
  "flate2",
- "num_cpus",
  "rayon",
  "tar",
  "walkdir",
@@ -3181,9 +3169,9 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.7.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
+checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
 dependencies = [
  "either",
  "rayon-core",
@@ -3191,14 +3179,12 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.11.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
+checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
 dependencies = [
- "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "num_cpus",
 ]
 
 [[package]]
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index e71f421659e..48421ff7140 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -146,37 +146,49 @@ pub fn print_crate<'a>(
     s.s.eof()
 }
 
-/// This makes printed token streams look slightly nicer,
-/// and also addresses some specific regressions described in #63896 and #73345.
-fn space_between(prev: &TokenTree, curr: &TokenTree) -> bool {
-    if let TokenTree::Token(token, _) = prev {
-        // No space after these tokens, e.g. `x.y`, `$e`
-        // (The carets point to `prev`.)       ^     ^
-        if matches!(token.kind, token::Dot | token::Dollar) {
-            return false;
-        }
-        if let token::DocComment(comment_kind, ..) = token.kind {
-            return comment_kind != CommentKind::Line;
-        }
-    }
-    match curr {
-        // No space before these tokens, e.g. `foo,`, `println!`, `x.y`
-        // (The carets point to `curr`.)          ^           ^     ^
+/// Should two consecutive tokens be printed with a space between them?
+///
+/// Note: some old proc macros parse pretty-printed output, so changes here can
+/// break old code. For example:
+/// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,`
+/// - #73345: `#[allow(unused)] must be printed rather than `# [allow(unused)]
+///
+fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
+    use token::*;
+    use Delimiter::*;
+    use TokenTree::Delimited as Del;
+    use TokenTree::Token as Tok;
+
+    // Each match arm has one or more examples in comments. The default is to
+    // insert space between adjacent tokens, except for the cases listed in
+    // this match.
+    match (tt1, tt2) {
+        // No space after line doc comments.
+        (Tok(Token { kind: DocComment(CommentKind::Line, ..), .. }, _), _) => false,
+
+        // `.` + ANYTHING: `x.y`, `tup.0`
+        // `$` + ANYTHING: `$e`
+        (Tok(Token { kind: Dot | Dollar, .. }, _), _) => false,
+
+        // ANYTHING + `,`: `foo,`
+        // ANYTHING + `.`: `x.y`, `tup.0`
+        // ANYTHING + `!`: `foo! { ... }`
         //
-        // FIXME: having `Not` here works well for macro invocations like
-        // `println!()`, but is bad when `!` means "logical not" or "the never
-        // type", where the lack of space causes ugliness like this:
-        // `Fn() ->!`, `x =! y`, `if! x { f(); }`.
-        TokenTree::Token(token, _) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
-        // No space before parentheses if preceded by these tokens, e.g. `foo(...)`
-        TokenTree::Delimited(_, Delimiter::Parenthesis, _) => {
-            !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }, _))
-        }
-        // No space before brackets if preceded by these tokens, e.g. `#[...]`
-        TokenTree::Delimited(_, Delimiter::Bracket, _) => {
-            !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }, _))
-        }
-        TokenTree::Delimited(..) => true,
+        // FIXME: Incorrect cases:
+        // - Logical not: `x =! y`, `if! x { f(); }`
+        // - Never type: `Fn() ->!`
+        (_, Tok(Token { kind: Comma | Dot | Not, .. }, _)) => false,
+
+        // IDENT + `(`: `f(3)`
+        //
+        // FIXME: Incorrect cases:
+        // - Let: `let(a, b) = (1, 2)`
+        (Tok(Token { kind: Ident(..), .. }, _), Del(_, Parenthesis, _)) => false,
+
+        // `#` + `[`: `#[attr]`
+        (Tok(Token { kind: Pound, .. }, _), Del(_, Bracket, _)) => false,
+
+        _ => true,
     }
 }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 8e66083a390..d3081695523 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -4,11 +4,11 @@ use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
 use rustc_session::config::{
     build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
-    DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, Input,
-    InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli,
-    MirSpanview, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
-    Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion,
-    TraitSolver, WasiExecModel,
+    DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
+    InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained,
+    LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, OutFileName,
+    OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip,
+    SwitchWithOptPath, SymbolManglingVersion, TraitSolver, WasiExecModel,
 };
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
@@ -748,7 +748,7 @@ fn test_unstable_options_tracking_hash() {
     );
     tracked!(codegen_backend, Some("abc".to_string()));
     tracked!(crate_attr, vec!["abc".to_string()]);
-    tracked!(cross_crate_inline_threshold, Some(200));
+    tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 4d0e261ed1f..261d9dd448d 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -7,6 +7,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::config::InliningThreshold;
 use rustc_session::config::OptLevel;
 
 pub fn provide(providers: &mut Providers) {
@@ -54,6 +55,12 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
         return false;
     }
 
+    let threshold = match tcx.sess.opts.unstable_opts.cross_crate_inline_threshold {
+        InliningThreshold::Always => return true,
+        InliningThreshold::Sometimes(threshold) => threshold,
+        InliningThreshold::Never => return false,
+    };
+
     let mir = tcx.optimized_mir(def_id);
     let mut checker =
         CostChecker { tcx, callee_body: mir, calls: 0, statements: 0, landing_pads: 0, resumes: 0 };
@@ -61,8 +68,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     checker.calls == 0
         && checker.resumes == 0
         && checker.landing_pads == 0
-        && checker.statements
-            <= tcx.sess.opts.unstable_opts.cross_crate_inline_threshold.unwrap_or(100)
+        && checker.statements <= threshold
 }
 
 struct CostChecker<'b, 'tcx> {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 930fb693eb6..f745bc390ca 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3161,10 +3161,10 @@ impl PpMode {
 pub(crate) mod dep_tracking {
     use super::{
         BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
-        ErrorOutputType, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
-        LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius,
-        RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
-        SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
+        ErrorOutputType, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto,
+        LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
+        Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm,
+        SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
@@ -3270,6 +3270,7 @@ pub(crate) mod dep_tracking {
         LanguageIdentifier,
         TraitSolver,
         Polonius,
+        InliningThreshold,
     );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
@@ -3435,3 +3436,16 @@ impl Polonius {
         matches!(self, Polonius::Next)
     }
 }
+
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum InliningThreshold {
+    Always,
+    Sometimes(usize),
+    Never,
+}
+
+impl Default for InliningThreshold {
+    fn default() -> Self {
+        Self::Sometimes(100)
+    }
+}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 7510a41485a..964a26e94fe 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -428,6 +428,8 @@ mod desc {
         "one of supported execution strategies (`same-thread`, or `cross-thread`)";
     pub const parse_dump_solver_proof_tree: &str = "one of: `always`, `on-request`, `on-error`";
     pub const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `unsplit-debuginfo`, `split-debuginfo`, `split-debuginfo-path`, `object`, `all`";
+    pub const parse_inlining_threshold: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
 }
 
 mod parse {
@@ -1310,6 +1312,26 @@ mod parse {
         };
         true
     }
+
+    pub(crate) fn parse_inlining_threshold(slot: &mut InliningThreshold, v: Option<&str>) -> bool {
+        match v {
+            Some("always" | "yes") => {
+                *slot = InliningThreshold::Always;
+            }
+            Some("never") => {
+                *slot = InliningThreshold::Never;
+            }
+            Some(v) => {
+                if let Ok(threshold) = v.parse() {
+                    *slot = InliningThreshold::Sometimes(threshold);
+                } else {
+                    return false;
+                }
+            }
+            None => return false,
+        }
+        true
+    }
 }
 
 options! {
@@ -1479,7 +1501,7 @@ options! {
         "combine CGUs into a single one"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
         "inject the given attribute in the crate"),
-    cross_crate_inline_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
+    cross_crate_inline_threshold: InliningThreshold = (InliningThreshold::Sometimes(100), parse_inlining_threshold, [TRACKED],
         "threshold to allow cross crate inlining of functions"),
     debug_info_for_profiling: bool = (false, parse_bool, [TRACKED],
         "emit discriminators and other data necessary for AutoFDO"),
diff --git a/config.example.toml b/config.example.toml
index 4984cf8ba1e..e5df28a49af 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -30,7 +30,7 @@
 #
 # If `change-id` does not match the version that is currently running,
 # `x.py` will prompt you to update it and check the related PR for more details.
-change-id = 117435
+change-id = 116881
 
 # =============================================================================
 # Tweaking how LLVM is compiled
@@ -42,11 +42,15 @@ change-id = 117435
 # Unless you're developing for a target where Rust CI doesn't build a compiler
 # toolchain or changing LLVM locally, you probably want to leave this enabled.
 #
-# All tier 1 targets are currently supported; set this to `"if-available"` if
-# you are not sure whether you're on a tier 1 target.
+# Set this to `"if-available"` if you are not sure whether you're on a tier 1 
+# target. All tier 1 targets are currently supported;
 #
 # We also currently only support this when building LLVM for the build triple.
 #
+# Set this to `"if-unchanged"` to only download if the llvm-project have not 
+# been modified. (If there are no changes or if built from tarball source, 
+# the logic is the same as "if-available")
+#
 # Note that many of the LLVM options are not currently supported for
 # downloading. Currently only the "assertions" option can be toggled.
 #download-ci-llvm = if rust.channel == "dev" { "if-available" } else { false }
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 346bfb30fec..57113b0ec62 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -181,16 +181,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "crossbeam-channel"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
-]
-
-[[package]]
 name = "crossbeam-deque"
 version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -324,15 +314,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
-name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
-[[package]]
 name = "hex"
 version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -444,16 +425,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "num_cpus"
-version = "1.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
 name = "object"
 version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -514,25 +485,22 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.6.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
+checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
 dependencies = [
- "crossbeam-deque",
  "either",
  "rayon-core",
 ]
 
 [[package]]
 name = "rayon-core"
-version = "1.10.1"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
+checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
 dependencies = [
- "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "num_cpus",
 ]
 
 [[package]]
diff --git a/src/bootstrap/defaults/config.codegen.toml b/src/bootstrap/defaults/config.codegen.toml
index 113df88d7c3..7c33ce958c9 100644
--- a/src/bootstrap/defaults/config.codegen.toml
+++ b/src/bootstrap/defaults/config.codegen.toml
@@ -10,7 +10,7 @@ assertions = true
 # enable warnings during the llvm compilation
 enable-warnings = true
 # build llvm from source
-download-ci-llvm = false
+download-ci-llvm = "if-unchanged"
 
 [rust]
 # This enables `RUSTC_LOG=debug`, avoiding confusing situations
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index ffc38057900..9998fe2f5db 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/113996
+Last change is for: https://github.com/rust-lang/rust/pull/116881
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 6e80c55c8ce..950845b736f 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2219,23 +2219,19 @@ impl Step for RustDev {
         builder.ensure(crate::core::build_steps::llvm::Lld { target });
 
         let src_bindir = builder.llvm_out(target).join("bin");
-        // If updating this list, you likely want to change
+        // If updating this, you likely want to change
         // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
         // will not pick up the extra file until LLVM gets bumped.
-        for bin in &[
-            "llvm-config",
-            "llvm-ar",
-            "llvm-objdump",
-            "llvm-profdata",
-            "llvm-bcanalyzer",
-            "llvm-cov",
-            "llvm-dwp",
-            "llvm-nm",
-            "llvm-dwarfdump",
-            "llvm-dis",
-            "llvm-tblgen",
-        ] {
-            tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
+        // We should include all the build artifacts obtained from a source build,
+        // so that you can use the downloadable LLVM as if you’ve just run a full source build.
+        if src_bindir.exists() {
+            for entry in walkdir::WalkDir::new(&src_bindir) {
+                let entry = t!(entry);
+                if entry.file_type().is_file() && !entry.path_is_symlink() {
+                    let name = entry.file_name().to_str().unwrap();
+                    tarball.add_file(src_bindir.join(name), "bin", 0o755);
+                }
+            }
         }
 
         // We don't build LLD on some platforms, so only add it if it exists
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index f2a185f70fe..e3fd942fc38 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -887,7 +887,7 @@ tool_doc!(
     "src/tools/rustfmt",
     crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]
 );
-tool_doc!(Clippy, "clippy", "src/tools/clippy", crates = ["clippy_utils"]);
+tool_doc!(Clippy, "clippy", "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]);
 tool_doc!(Miri, "miri", "src/tools/miri", crates = ["miri"]);
 tool_doc!(
     Cargo,
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index b4540641bfa..04a16443770 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -147,6 +147,15 @@ impl Step for Profile {
     }
 
     fn run(self, builder: &Builder<'_>) {
+        // During ./x.py setup once you select the codegen profile.
+        // The submodule will be downloaded. It does not work in the
+        // tarball case since they don't include Git and submodules
+        // are already included.
+        if !builder.rust_info().is_from_tarball() {
+            if self == Profile::Codegen {
+                builder.update_submodule(&Path::new("src/llvm-project"));
+            }
+        }
         setup(&builder.build.config, self)
     }
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index a871399453e..2eb5d06bcb3 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -19,6 +19,7 @@ use std::process::Command;
 use std::str::FromStr;
 
 use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
+use crate::core::build_steps::llvm;
 use crate::core::config::flags::{Color, Flags, Warnings};
 use crate::utils::cache::{Interned, INTERNER};
 use crate::utils::channel::{self, GitInfo};
@@ -1530,17 +1531,7 @@ impl Config {
             config.llvm_build_config = llvm.build_config.clone().unwrap_or(Default::default());
 
             let asserts = llvm_assertions.unwrap_or(false);
-            config.llvm_from_ci = match llvm.download_ci_llvm {
-                Some(StringOrBool::String(s)) => {
-                    assert_eq!(s, "if-available", "unknown option `{s}` for download-ci-llvm");
-                    crate::core::build_steps::llvm::is_ci_llvm_available(&config, asserts)
-                }
-                Some(StringOrBool::Bool(b)) => b,
-                None => {
-                    config.channel == "dev"
-                        && crate::core::build_steps::llvm::is_ci_llvm_available(&config, asserts)
-                }
-            };
+            config.llvm_from_ci = config.parse_download_ci_llvm(llvm.download_ci_llvm, asserts);
 
             if config.llvm_from_ci {
                 // None of the LLVM options, except assertions, are supported
@@ -2104,6 +2095,94 @@ impl Config {
 
         Some(commit.to_string())
     }
+
+    fn parse_download_ci_llvm(
+        &self,
+        download_ci_llvm: Option<StringOrBool>,
+        asserts: bool,
+    ) -> bool {
+        match download_ci_llvm {
+            None => self.channel == "dev" && llvm::is_ci_llvm_available(&self, asserts),
+            Some(StringOrBool::Bool(b)) => b,
+            Some(StringOrBool::String(s)) if s == "if-available" => {
+                llvm::is_ci_llvm_available(&self, asserts)
+            }
+            Some(StringOrBool::String(s)) if s == "if-unchanged" => {
+                // Git is needed to track modifications here, but tarball source is not available.
+                // If not modified here or built through tarball source, we maintain consistency
+                // with '"if available"'.
+                if !self.rust_info.is_from_tarball()
+                    && self
+                        .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true)
+                        .is_none()
+                {
+                    // there are some untracked changes in the the given paths.
+                    false
+                } else {
+                    llvm::is_ci_llvm_available(&self, asserts)
+                }
+            }
+            Some(StringOrBool::String(other)) => {
+                panic!("unrecognized option for download-ci-llvm: {:?}", other)
+            }
+        }
+    }
+
+    /// Returns the last commit in which any of `modified_paths` were changed,
+    /// or `None` if there are untracked changes in the working directory and `if_unchanged` is true.
+    pub fn last_modified_commit(
+        &self,
+        modified_paths: &[&str],
+        option_name: &str,
+        if_unchanged: bool,
+    ) -> Option<String> {
+        // Handle running from a directory other than the top level
+        let top_level = output(self.git().args(&["rev-parse", "--show-toplevel"]));
+        let top_level = top_level.trim_end();
+
+        // Look for a version to compare to based on the current commit.
+        // Only commits merged by bors will have CI artifacts.
+        let merge_base = output(
+            self.git()
+                .arg("rev-list")
+                .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
+                .args(&["-n1", "--first-parent", "HEAD"]),
+        );
+        let commit = merge_base.trim_end();
+        if commit.is_empty() {
+            println!("error: could not find commit hash for downloading components from CI");
+            println!("help: maybe your repository history is too shallow?");
+            println!("help: consider disabling `{option_name}`");
+            println!("help: or fetch enough history to include one upstream commit");
+            crate::exit!(1);
+        }
+
+        // Warn if there were changes to the compiler or standard library since the ancestor commit.
+        let mut git = self.git();
+        git.args(&["diff-index", "--quiet", &commit, "--"]);
+
+        for path in modified_paths {
+            git.arg(format!("{top_level}/{path}"));
+        }
+
+        let has_changes = !t!(git.status()).success();
+        if has_changes {
+            if if_unchanged {
+                if self.verbose > 0 {
+                    println!(
+                        "warning: saw changes to one of {modified_paths:?} since {commit}; \
+                            ignoring `{option_name}`"
+                    );
+                }
+                return None;
+            }
+            println!(
+                "warning: `{option_name}` is enabled, but there are changes to one of {modified_paths:?}"
+            );
+        }
+
+        Some(commit.to_string())
+    }
 }
 
 fn set<T>(field: &mut T, val: Option<T>) {
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 27922c9fbbe..fc3413a3c81 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -77,7 +77,7 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
 ///
 /// If you make any major changes (such as adding new values or changing default values), please
 /// ensure that the associated PR ID is added to the end of this list.
-pub const CONFIG_CHANGE_HISTORY: &[usize] = &[115898, 116998, 117435];
+pub const CONFIG_CHANGE_HISTORY: &[usize] = &[115898, 116998, 117435, 116881];
 
 /// Extra --check-cfg to add when building
 /// (Mode restriction, config name, config values (if any))
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 8b4d673d831..1b27b77b3e6 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -41,6 +41,7 @@
     - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md)
     - [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md)
     - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
+    - [powerpc64-ibm-aix](platform-support/aix.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 6a979869a59..907e9c59f31 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -310,7 +310,7 @@ target | std | host | notes
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
 [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64
-`powerpc64-ibm-aix` | ? |  | 64-bit AIX (7.2 and newer)
+[`powerpc64-ibm-aix`](platform-support/aix.md) | ? |  | 64-bit AIX (7.2 and newer)
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
 `riscv32im-unknown-none-elf` | * |  | Bare RISC-V (RV32IM ISA)
diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md
new file mode 100644
index 00000000000..c3ce71a1835
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/aix.md
@@ -0,0 +1,26 @@
+# `powerpc64-ibm-aix`
+
+**Tier: 3**
+
+Rust for AIX operating system, currently only 64-bit PowerPC is supported.
+
+## Target maintainers
+
+- QIU Chaofan `qiucofan@cn.ibm.com`, https://github.com/ecnelises
+- Kai LUO, `lkail@cn.ibm.com`, https://github.com/bzEq
+
+## Requirements
+
+This target supports host tools, std and alloc. This target cannot be cross-compiled as for now, mainly because of the unavailability of system linker on other platforms.
+
+Binary built for this target is expected to run on Power7 or newer CPU, and AIX 7.2 or newer version.
+
+Binary format of this platform is [XCOFF](https://www.ibm.com/docs/en/aix/7.2?topic=formats-xcoff-object-file-format). Archive file format is ['AIX big format'](https://www.ibm.com/docs/en/aix/7.2?topic=formats-ar-file-format-big).
+
+## Testing
+
+This target supports running test suites natively, but it's not available to cross-compile and execute in emulator.
+
+## Interoperability with C code
+
+This target supports C code. C code compiled by XL, Open XL and Clang are compatible with Rust. Typical triple of AIX on 64-bit PowerPC of these compilers are also `powerpc64-ibm-aix`.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e6e2d60f2e5..1b7ca7bf7dd 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2534,7 +2534,8 @@ fn clean_generic_args<'tcx>(
                     }
                     hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
                     hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
-                    // FIXME(effects): This will still emit `<true>` for non-const impls of const traits
+                    // Checking for `#[rustc_host]` on the `AnonConst`  not only accounts for the case
+                    // where the argument is `host` but for all possible cases (e.g., `true`, `false`).
                     hir::GenericArg::Const(ct)
                         if cx.tcx.has_attr(ct.value.def_id, sym::rustc_host) =>
                     {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index ca1b782492c..9ff00c1946f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -124,11 +124,7 @@ pub(crate) fn ty_args_to_args<'tcx>(
             )))
         }
         GenericArgKind::Const(ct) => {
-            // FIXME(effects): this relies on the host effect being called `host`, which users could also name
-            // their const generics.
-            // FIXME(effects): this causes `host = true` and `host = false` generics to also be emitted.
-            if let ty::ConstKind::Param(p) = ct.kind()
-                && p.name == sym::host
+            if let ty::GenericParamDefKind::Const { is_host_effect: true, .. } = params[index].kind
             {
                 return None;
             }
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 65e297d1ec0dee1a74800efe600b8dc163bcf5d
+Subproject 7046d992f9f32ba209a8079f662ebccf9da8de2
diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml
index 471f2b5ac73..cdd867c5f15 100644
--- a/src/tools/rust-installer/Cargo.toml
+++ b/src/tools/rust-installer/Cargo.toml
@@ -16,7 +16,6 @@ rayon = "1.0"
 tar = "0.4.38"
 walkdir = "2"
 xz2 = "0.1.4"
-num_cpus = "1"
 
 [dependencies.clap]
 features = ["derive"]
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index b10cccc79f6..7ad75f089f3 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -228,7 +228,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "ena",
     "equivalent",
     "errno",
-    "errno-dragonfly",
     "expect-test",
     "fallible-iterator", // dependency of `thorin`
     "fastrand",
diff --git a/tests/codegen/cross-crate-inlining/always-inline.rs b/tests/codegen/cross-crate-inlining/always-inline.rs
new file mode 100644
index 00000000000..f3f08bf116a
--- /dev/null
+++ b/tests/codegen/cross-crate-inlining/always-inline.rs
@@ -0,0 +1,13 @@
+// compile-flags: -O
+// aux-build:always.rs
+
+#![crate_type = "lib"]
+
+extern crate always;
+
+// Check that we inline a cross-crate call, even though it isn't a leaf
+#[no_mangle]
+pub fn outer() -> String {
+    // CHECK-NOT: call {{.*}}stem_fn
+    always::stem_fn()
+}
diff --git a/tests/codegen/cross-crate-inlining/auxiliary/always.rs b/tests/codegen/cross-crate-inlining/auxiliary/always.rs
new file mode 100644
index 00000000000..3670307ec81
--- /dev/null
+++ b/tests/codegen/cross-crate-inlining/auxiliary/always.rs
@@ -0,0 +1,20 @@
+// compile-flags: -O -Zcross-crate-inline-threshold=always
+
+#![crate_type = "lib"]
+
+// This function *looks* like it contains a call, but that call will be optimized out by MIR
+// optimizations.
+pub fn leaf_fn() -> String {
+    String::new()
+}
+
+// This function contains a call, even after MIR optimizations. It is only eligible for
+// cross-crate-inlining with "always".
+pub fn stem_fn() -> String {
+    inner()
+}
+
+#[inline(never)]
+fn inner() -> String {
+    String::from("test")
+}
diff --git a/tests/codegen/cross-crate-inlining/auxiliary/leaf.rs b/tests/codegen/cross-crate-inlining/auxiliary/leaf.rs
new file mode 100644
index 00000000000..963f087f22d
--- /dev/null
+++ b/tests/codegen/cross-crate-inlining/auxiliary/leaf.rs
@@ -0,0 +1,20 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// This function *looks* like it contains a call, but that call will be optimized out by MIR
+// optimizations.
+pub fn leaf_fn() -> String {
+    String::new()
+}
+
+// This function contains a call, even after MIR optimizations. It is only eligible for
+// cross-crate-inlining with "always".
+pub fn stem_fn() -> String {
+    inner()
+}
+
+#[inline(never)]
+fn inner() -> String {
+    String::from("test")
+}
diff --git a/tests/codegen/cross-crate-inlining/auxiliary/never.rs b/tests/codegen/cross-crate-inlining/auxiliary/never.rs
new file mode 100644
index 00000000000..e222a6dea38
--- /dev/null
+++ b/tests/codegen/cross-crate-inlining/auxiliary/never.rs
@@ -0,0 +1,20 @@
+// compile-flags: -O -Zcross-crate-inline-threshold=never
+
+#![crate_type = "lib"]
+
+// This function *looks* like it contains a call, but that call will be optimized out by MIR
+// optimizations.
+pub fn leaf_fn() -> String {
+    String::new()
+}
+
+// This function contains a call, even after MIR optimizations. It is only eligible for
+// cross-crate-inlining with "always".
+pub fn stem_fn() -> String {
+    inner()
+}
+
+#[inline(never)]
+fn inner() -> String {
+    String::from("test")
+}
diff --git a/tests/codegen/cross-crate-inlining/leaf-inlining.rs b/tests/codegen/cross-crate-inlining/leaf-inlining.rs
new file mode 100644
index 00000000000..73b1a520b06
--- /dev/null
+++ b/tests/codegen/cross-crate-inlining/leaf-inlining.rs
@@ -0,0 +1,20 @@
+// compile-flags: -O -Zcross-crate-inline-threshold=yes
+// aux-build:leaf.rs
+
+#![crate_type = "lib"]
+
+extern crate leaf;
+
+// Check that we inline a leaf cross-crate call
+#[no_mangle]
+pub fn leaf_outer() -> String {
+    // CHECK-NOT: call {{.*}}leaf_fn
+    leaf::leaf_fn()
+}
+
+// Check that we do not inline a non-leaf cross-crate call
+#[no_mangle]
+pub fn stem_outer() -> String {
+    // CHECK: call {{.*}}stem_fn
+    leaf::stem_fn()
+}
diff --git a/tests/codegen/cross-crate-inlining/never-inline.rs b/tests/codegen/cross-crate-inlining/never-inline.rs
new file mode 100644
index 00000000000..4e7bc3e5154
--- /dev/null
+++ b/tests/codegen/cross-crate-inlining/never-inline.rs
@@ -0,0 +1,13 @@
+// compile-flags: -O
+// aux-build:never.rs
+
+#![crate_type = "lib"]
+
+extern crate never;
+
+// Check that we do not inline a cross-crate call, even though it is a leaf
+#[no_mangle]
+pub fn outer() -> String {
+    // CHECK: call {{.*}}leaf_fn
+    never::leaf_fn()
+}
diff --git a/tests/rustdoc/const-effect-param.rs b/tests/rustdoc/const-effect-param.rs
index f50a9b96d81..b6379c05a85 100644
--- a/tests/rustdoc/const-effect-param.rs
+++ b/tests/rustdoc/const-effect-param.rs
@@ -1,3 +1,5 @@
+// Check that we don't render host effect parameters & arguments.
+
 #![crate_name = "foo"]
 #![feature(effects, const_trait_impl)]
 
diff --git a/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs b/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs
new file mode 100644
index 00000000000..b0c21ffaeb9
--- /dev/null
+++ b/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs
@@ -0,0 +1,16 @@
+#![feature(effects, const_trait_impl)]
+
+#[const_trait]
+pub trait Resource {}
+
+pub const fn load<R: ~const Resource>() -> i32 {
+    0
+}
+
+pub const fn lock<R: Resource>() {}
+
+#[allow(non_upper_case_globals)]
+pub trait Clash<const host: u64> {}
+
+#[allow(non_upper_case_globals)]
+pub const fn clash<T: Clash<host>, const host: u64>() {}
diff --git a/tests/rustdoc/inline_cross/auxiliary/const-fn.rs b/tests/rustdoc/inline_cross/auxiliary/const-fn.rs
deleted file mode 100644
index 26332b419b6..00000000000
--- a/tests/rustdoc/inline_cross/auxiliary/const-fn.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![feature(effects)]
-
-pub const fn load() -> i32 {
-    0
-}
diff --git a/tests/rustdoc/inline_cross/const-effect-param.rs b/tests/rustdoc/inline_cross/const-effect-param.rs
new file mode 100644
index 00000000000..1d003e28f36
--- /dev/null
+++ b/tests/rustdoc/inline_cross/const-effect-param.rs
@@ -0,0 +1,29 @@
+// Regression test for issue #116629.
+// Check that we don't render host effect parameters & arguments.
+
+// aux-crate:const_effect_param=const-effect-param.rs
+// edition: 2021
+#![crate_name = "user"]
+
+// Don't render the host param on `load` and the host arg `host` passed to `Resource`.
+// @has user/fn.load.html
+// @has - '//pre[@class="rust item-decl"]' "pub const fn load<R>() -> i32\
+//     where \
+//         R: Resource"
+pub use const_effect_param::load;
+
+// Don't render the host arg `true` passed to `Resource`.
+// @has user/fn.lock.html
+// @has - '//pre[@class="rust item-decl"]' "pub const fn lock<R>()\
+//     where \
+//         R: Resource"
+pub use const_effect_param::lock;
+
+// Regression test for an issue introduced in PR #116670.
+// Don't hide the const param `host` since it actually isn't the host effect param.
+// @has user/fn.clash.html
+// @has - '//pre[@class="rust item-decl"]' \
+//    "pub const fn clash<T, const host: u64>()\
+//     where \
+//         T: Clash<host>"
+pub use const_effect_param::clash;
diff --git a/tests/rustdoc/inline_cross/const-fn.rs b/tests/rustdoc/inline_cross/const-fn.rs
deleted file mode 100644
index 24934b873c2..00000000000
--- a/tests/rustdoc/inline_cross/const-fn.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Regression test for issue #116629.
-// Check that we render the correct generic params of const fn
-
-// aux-crate:const_fn=const-fn.rs
-// edition: 2021
-#![crate_name = "user"]
-
-// @has user/fn.load.html
-// @has - '//pre[@class="rust item-decl"]' "pub const fn load() -> i32"
-pub use const_fn::load;
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
index f1bbd4a6210..70ca00285c4 100644
--- a/tests/ui/macros/stringify.rs
+++ b/tests/ui/macros/stringify.rs
@@ -115,6 +115,7 @@ fn test_expr() {
         "a + b * c - d + -1 * -2 - -3",
         "a + b * c - d + - 1 * - 2 - - 3"
     );
+    c2!(expr, [ x = !y ], "x = !y", "x =! y"); // FIXME
 
     // ExprKind::Unary
     c2!(expr, [ *expr ], "*expr", "* expr");
@@ -137,6 +138,7 @@ fn test_expr() {
 
     // ExprKind::If
     c1!(expr, [ if true {} ], "if true {}");
+    c2!(expr, [ if !true {} ], "if !true {}", "if! true {}"); // FIXME
     c2!(expr,
         [ if ::std::blah() { } else { } ],
         "if ::std::blah() {} else {}",
@@ -799,3 +801,32 @@ fn test_vis() {
     assert_eq!(inherited_vis!(struct), "");
     assert_eq!(stringify!(), "");
 }
+
+macro_rules! p {
+    ([$($tt:tt)*], $s:literal) => {
+        assert_eq!(stringify!($($tt)*), $s);
+    };
+}
+
+#[test]
+fn test_punct() {
+    // For all these cases, we must preserve spaces between the tokens.
+    // Otherwise, any old proc macro that parses pretty-printed code might glue
+    // together tokens that shouldn't be glued.
+    p!([ = = < < <= <= == == != != >= >= > > ], "= = < < <= <= == == != != >= >= > >");
+    p!([ && && & & || || | | ! ! ], "&& && & & || || | |!!"); // FIXME
+    p!([ ~ ~ @ @ # # ], "~ ~ @ @ # #");
+    p!([ . . .. .. ... ... ..= ..=], ".... .. ... ... ..= ..="); // FIXME
+    p!([ , , ; ; : : :: :: ], ",, ; ; : : :: ::"); // FIXME
+    p!([ -> -> <- <- => =>], "-> -> <- <- => =>");
+    p!([ $ $ ? ? ' ' ], "$$? ? ' '"); // FIXME
+    p!([ + + += += - - -= -= * * *= *= / / /= /= ], "+ + += += - - -= -= * * *= *= / / /= /=");
+    p!([ % % %= %= ^ ^ ^= ^= << << <<= <<= >> >> >>= >>= ],
+        "% % %= %= ^ ^ ^= ^= << << <<= <<= >> >> >>= >>=");
+
+    // For these one we must insert spaces between adjacent tokens, again due
+    // to proc macros.
+    p!([ +! ?= |> >>@ --> <-- $$ =====> ], "+! ? = | > >> @ - -> <- - $$== == =>"); // FIXME
+    p!([ ,; ;, ** @@ $+$ >< <> ?? +== ], ", ; ;, * * @ @ $+ $> < < > ? ? += ="); // FIXME
+    p!([ :#!@|$=&*,+;*~? ], ": #! @ | $= & *, + ; * ~ ?"); // FIXME
+}