Auto merge of #138021 - workingjubilee:rollup-brhnycu, r=workingjubilee

Rollup of 6 pull requests

Successful merges:

 - #137077 (Postprocess bootstrap metrics into GitHub job summary)
 - #137373 (Compile run-make-support and run-make tests with the bootstrap compiler)
 - #137634 (Update `compiler-builtins` to 0.1.149)
 - #137667 (Add `dist::Gcc` build step)
 - #137722 (`librustdoc`: 2024 edition! 🎊)
 - #137947 (Do not install rustup on Rust for Linux job)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-03-05 02:43:15 +00:00
commit ac951d3799
46 changed files with 765 additions and 793 deletions

View file

@ -182,6 +182,13 @@ jobs:
- name: show the current environment
run: src/ci/scripts/dump-environment.sh
# Pre-build citool before the following step uninstalls rustup
# Build is into the build directory, to avoid modifying sources
- name: build citool
run: |
cd src/ci/citool
CARGO_TARGET_DIR=../../../build/citool cargo build
- name: run the build
# Redirect stderr to stdout to avoid reordering the two streams in the GHA logs.
run: src/ci/scripts/run-build-from-ci.sh 2>&1
@ -218,6 +225,16 @@ jobs:
# erroring about invalid credentials instead.
if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1'
- name: postprocess metrics into the summary
run: |
if [ -f build/metrics.json ]; then
./build/citool/debug/citool postprocess-metrics build/metrics.json ${GITHUB_STEP_SUMMARY}
elif [ -f obj/build/metrics.json ]; then
./build/citool/debug/citool postprocess-metrics obj/build/metrics.json ${GITHUB_STEP_SUMMARY}
else
echo "No metrics.json found"
fi
- name: upload job metrics to DataDog
if: needs.calculate_matrix.outputs.run_type != 'pr'
env:

View file

@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644
[dependencies]
core = { path = "../core", public = true }
-compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std', 'no-f16-f128'] }
-compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std', 'no-f16-f128'] }
[dev-dependencies]
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }

View file

@ -1,8 +0,0 @@
/// "Signaling" trait used in impl trait to tag lifetimes that you may
/// need to capture but don't really need for other reasons.
/// Basically a workaround; see [this comment] for details.
///
/// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
pub trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}

View file

@ -48,7 +48,6 @@ pub use rustc_index::static_assert_size;
pub mod aligned;
pub mod base_n;
pub mod binary_search_util;
pub mod captures;
pub mod fingerprint;
pub mod flat_map_in_place;
pub mod flock;

View file

@ -61,9 +61,9 @@ dependencies = [
[[package]]
name = "compiler_builtins"
version = "0.1.148"
version = "0.1.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26137996631d90d2727b905b480fdcf8c4479fdbce7afd7f8e3796d689b33cc2"
checksum = "5c42734e0ccf0d9f953165770593a75306f0b24dda1aa03f115c70748726dbca"
dependencies = [
"cc",
"rustc-std-workspace-core",

View file

@ -12,7 +12,7 @@ edition = "2021"
[dependencies]
core = { path = "../core", public = true }
compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std'] }
[dev-dependencies]
rand = { version = "0.9.0", default-features = false, features = ["alloc"] }

View file

@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core", public = true }
compiler_builtins = { version = "=0.1.148" }
compiler_builtins = { version = "=0.1.150" }
unwind = { path = "../unwind" }
hashbrown = { version = "0.15", default-features = false, features = [
'rustc-dep-of-std',

View file

@ -2464,3 +2464,30 @@ impl Step for ReproducibleArtifacts {
if added_anything { Some(tarball.generate()) } else { None }
}
}
/// Tarball containing a prebuilt version of the libgccjit library,
/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
/// backend needing a prebuilt libLLVM).
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Gcc {
pub target: TargetSelection,
}
impl Step for Gcc {
type Output = GeneratedTarball;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("gcc")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Gcc { target: run.target });
}
fn run(self, builder: &Builder<'_>) -> Self::Output {
let tarball = Tarball::new(builder, "gcc", &self.target.triple);
let output = builder.ensure(super::gcc::Gcc { target: self.target });
tarball.add_file(output.libgccjit, ".", 0o644);
tarball.generate()
}
}

View file

@ -1242,59 +1242,6 @@ macro_rules! test {
};
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
pub struct RunMakeSupport {
pub compiler: Compiler,
pub target: TargetSelection,
}
impl Step for RunMakeSupport {
type Output = PathBuf;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() });
}
/// Builds run-make-support and returns the path to the resulting rlib.
fn run(self, builder: &Builder<'_>) -> PathBuf {
builder.ensure(compile::Std::new(self.compiler, self.target));
let cargo = tool::prepare_tool_cargo(
builder,
self.compiler,
Mode::ToolStd,
self.target,
Kind::Build,
"src/tools/run-make-support",
SourceType::InTree,
&[],
);
let _guard = builder.msg_tool(
Kind::Build,
Mode::ToolStd,
"run-make-support",
self.compiler.stage,
&self.compiler.host,
&self.target,
);
cargo.into_cmd().run(builder);
let lib_name = "librun_make_support.rlib";
let lib = builder.tools_dir(self.compiler).join(lib_name);
let cargo_out = builder.cargo_out(self.compiler, Mode::ToolStd, self.target).join(lib_name);
builder.copy_link(&cargo_out, &lib);
lib
}
}
/// Runs `cargo test` on the `src/tools/run-make-support` crate.
/// That crate is used by run-make tests.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -1446,40 +1393,7 @@ test!(Pretty {
only_hosts: true,
});
/// Special-handling is needed for `run-make`, so don't use `test!` for defining `RunMake`
/// tests.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RunMake {
pub compiler: Compiler,
pub target: TargetSelection,
}
impl Step for RunMake {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.suite_path("tests/run-make")
}
fn make_run(run: RunConfig<'_>) {
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() });
run.builder.ensure(RunMake { compiler, target: run.target });
}
fn run(self, builder: &Builder<'_>) {
builder.ensure(Compiletest {
compiler: self.compiler,
target: self.target,
mode: "run-make",
suite: "run-make",
path: "tests/run-make",
compare_mode: None,
});
}
}
test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true });
test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly", default: true });
@ -1722,6 +1636,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
host: target,
});
}
if suite == "run-make" {
builder.tool_exe(Tool::RunMakeSupport);
}
// Also provide `rust_test_helpers` for the host.
builder.ensure(TestHelpers { target: compiler.host });
@ -1774,6 +1691,11 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
};
cmd.arg("--cargo-path").arg(cargo_path);
// We need to pass the compiler that was used to compile run-make-support,
// because we have to use the same compiler to compile rmake.rs recipes.
let stage0_rustc_path = builder.compiler(0, compiler.host);
cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path));
}
// Avoid depending on rustdoc when we don't need it.

View file

@ -34,6 +34,12 @@ pub enum SourceType {
Submodule,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ToolArtifactKind {
Binary,
Library,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct ToolBuild {
compiler: Compiler,
@ -47,6 +53,8 @@ struct ToolBuild {
allow_features: &'static str,
/// Additional arguments to pass to the `cargo` invocation.
cargo_args: Vec<String>,
/// Whether the tool builds a binary or a library.
artifact_kind: ToolArtifactKind,
}
impl Builder<'_> {
@ -79,7 +87,7 @@ impl Builder<'_> {
/// for using this type as `type Output = ToolBuildResult;`
#[derive(Clone)]
pub struct ToolBuildResult {
/// Executable path of the corresponding tool that was built.
/// Artifact path of the corresponding tool that was built.
pub tool_path: PathBuf,
/// Compiler used to build the tool. For non-`ToolRustc` tools this is equal to `target_compiler`.
/// For `ToolRustc` this is one stage before of the `target_compiler`.
@ -179,8 +187,14 @@ impl Step for ToolBuild {
if tool == "tidy" {
tool = "rust-tidy";
}
let tool_path =
copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool);
let tool_path = match self.artifact_kind {
ToolArtifactKind::Binary => {
copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool)
}
ToolArtifactKind::Library => builder
.cargo_out(self.compiler, self.mode, self.target)
.join(format!("lib{tool}.rlib")),
};
ToolBuildResult { tool_path, build_compiler: self.compiler, target_compiler }
}
@ -330,6 +344,7 @@ macro_rules! bootstrap_tool {
$(,is_unstable_tool = $unstable:expr)*
$(,allow_features = $allow_features:expr)?
$(,submodules = $submodules:expr)?
$(,artifact_kind = $artifact_kind:expr)?
;
)+) => {
#[derive(PartialEq, Eq, Clone)]
@ -389,6 +404,7 @@ macro_rules! bootstrap_tool {
builder.require_submodule(submodule, None);
}
)*
builder.ensure(ToolBuild {
compiler: self.compiler,
target: self.target,
@ -407,7 +423,12 @@ macro_rules! bootstrap_tool {
},
extra_features: vec![],
allow_features: concat!($($allow_features)*),
cargo_args: vec![]
cargo_args: vec![],
artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* {
ToolArtifactKind::Library
} else {
ToolArtifactKind::Binary
}
})
}
}
@ -445,51 +466,14 @@ bootstrap_tool!(
WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump";
OptimizedDist, "src/tools/opt-dist", "opt-dist", submodules = &["src/tools/rustc-perf"];
RunMakeSupport, "src/tools/run-make-support", "run_make_support", artifact_kind = ToolArtifactKind::Library;
);
/// These are the submodules that are required for rustbook to work due to
/// depending on mdbook plugins.
pub static SUBMODULES_FOR_RUSTBOOK: &[&str] = &["src/doc/book", "src/doc/reference"];
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct OptimizedDist {
pub compiler: Compiler,
pub target: TargetSelection,
}
impl Step for OptimizedDist {
type Output = ToolBuildResult;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/opt-dist")
}
fn make_run(run: RunConfig<'_>) {
run.builder.ensure(OptimizedDist {
compiler: run.builder.compiler(0, run.builder.config.build),
target: run.target,
});
}
fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
// We need to ensure the rustc-perf submodule is initialized when building opt-dist since
// the tool requires it to be in place to run.
builder.require_submodule("src/tools/rustc-perf", None);
builder.ensure(ToolBuild {
compiler: self.compiler,
target: self.target,
tool: "opt-dist",
mode: Mode::ToolBootstrap,
path: "src/tools/opt-dist",
source_type: SourceType::InTree,
extra_features: Vec::new(),
allow_features: "",
cargo_args: Vec::new(),
})
}
}
/// The [rustc-perf](https://github.com/rust-lang/rustc-perf) benchmark suite, which is added
/// as a submodule at `src/tools/rustc-perf`.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
@ -529,6 +513,7 @@ impl Step for RustcPerf {
// Only build the collector package, which is used for benchmarking through
// a CLI.
cargo_args: vec!["-p".to_string(), "collector".to_string()],
artifact_kind: ToolArtifactKind::Binary,
};
let res = builder.ensure(tool.clone());
// We also need to symlink the `rustc-fake` binary to the corresponding directory,
@ -586,6 +571,7 @@ impl Step for ErrorIndex {
extra_features: Vec::new(),
allow_features: "",
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
})
}
}
@ -621,6 +607,7 @@ impl Step for RemoteTestServer {
extra_features: Vec::new(),
allow_features: "",
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
})
}
}
@ -725,6 +712,7 @@ impl Step for Rustdoc {
extra_features,
allow_features: "",
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
});
// don't create a stage0-sysroot/bin directory.
@ -779,6 +767,7 @@ impl Step for Cargo {
extra_features: Vec::new(),
allow_features: "",
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
})
}
}
@ -827,6 +816,7 @@ impl Step for LldWrapper {
extra_features: Vec::new(),
allow_features: "",
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
});
let libdir_bin = builder.sysroot_target_bindir(self.target_compiler, target);
@ -887,6 +877,7 @@ impl Step for RustAnalyzer {
source_type: SourceType::InTree,
allow_features: RustAnalyzer::ALLOW_FEATURES,
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
})
}
}
@ -931,6 +922,7 @@ impl Step for RustAnalyzerProcMacroSrv {
source_type: SourceType::InTree,
allow_features: RustAnalyzer::ALLOW_FEATURES,
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
});
// Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/`
@ -985,6 +977,7 @@ impl Step for LlvmBitcodeLinker {
extra_features: self.extra_features,
allow_features: "",
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
});
if tool_result.target_compiler.stage > 0 {
@ -1164,6 +1157,7 @@ fn run_tool_build_step(
source_type: SourceType::InTree,
allow_features: "",
cargo_args: vec![],
artifact_kind: ToolArtifactKind::Binary,
});
// FIXME: This should just be an if-let-chain, but those are unstable.
@ -1242,6 +1236,7 @@ impl Step for TestFloatParse {
extra_features: Vec::new(),
allow_features: "",
cargo_args: Vec::new(),
artifact_kind: ToolArtifactKind::Binary,
})
}
}

View file

@ -1072,6 +1072,7 @@ impl<'a> Builder<'a> {
dist::PlainSourceTarball,
dist::BuildManifest,
dist::ReproducibleArtifacts,
dist::Gcc
),
Kind::Install => describe!(
install::Docs,

View file

@ -200,6 +200,14 @@ impl BuildMetrics {
}
};
invocations.push(JsonInvocation {
// The command-line invocation with which bootstrap was invoked.
// Skip the first argument, as it is a potentially long absolute
// path that is not interesting.
cmdline: std::env::args_os()
.skip(1)
.map(|arg| arg.to_string_lossy().to_string())
.collect::<Vec<_>>()
.join(" "),
start_time: state
.invocation_start
.duration_since(SystemTime::UNIX_EPOCH)

View file

@ -1,3 +1,5 @@
use std::time::Duration;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
@ -12,6 +14,8 @@ pub struct JsonRoot {
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct JsonInvocation {
// Remembers the command-line invocation with which bootstrap was invoked.
pub cmdline: String,
// Unix timestamp in seconds
//
// This is necessary to easily correlate this invocation with logs or other data.
@ -98,3 +102,87 @@ fn null_as_f64_nan<'de, D: serde::Deserializer<'de>>(d: D) -> Result<f64, D::Err
use serde::Deserialize as _;
Option::<f64>::deserialize(d).map(|f| f.unwrap_or(f64::NAN))
}
/// Represents a single bootstrap step, with the accumulated duration of all its children.
#[derive(Clone, Debug)]
pub struct BuildStep {
pub r#type: String,
pub children: Vec<BuildStep>,
pub duration: Duration,
}
impl BuildStep {
/// Create a `BuildStep` representing a single invocation of bootstrap.
/// The most important thing is that the build step aggregates the
/// durations of all children, so that it can be easily accessed.
pub fn from_invocation(invocation: &JsonInvocation) -> Self {
fn parse(node: &JsonNode) -> Option<BuildStep> {
match node {
JsonNode::RustbuildStep {
type_: kind,
children,
duration_excluding_children_sec,
..
} => {
let children: Vec<_> = children.into_iter().filter_map(parse).collect();
let children_duration = children.iter().map(|c| c.duration).sum::<Duration>();
Some(BuildStep {
r#type: kind.to_string(),
children,
duration: children_duration
+ Duration::from_secs_f64(*duration_excluding_children_sec),
})
}
JsonNode::TestSuite(_) => None,
}
}
let duration = Duration::from_secs_f64(invocation.duration_including_children_sec);
let children: Vec<_> = invocation.children.iter().filter_map(parse).collect();
Self { r#type: "total".to_string(), children, duration }
}
pub fn find_all_by_type(&self, r#type: &str) -> Vec<&Self> {
let mut result = Vec::new();
self.find_by_type(r#type, &mut result);
result
}
fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a Self>) {
if self.r#type == r#type {
result.push(self);
}
for child in &self.children {
child.find_by_type(r#type, result);
}
}
}
/// Writes build steps into a nice indented table.
pub fn format_build_steps(root: &BuildStep) -> String {
use std::fmt::Write;
let mut substeps: Vec<(u32, &BuildStep)> = Vec::new();
fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) {
substeps.push((level, step));
for child in &step.children {
visit(child, level + 1, substeps);
}
}
visit(root, 0, &mut substeps);
let mut output = String::new();
for (level, step) in substeps {
let label = format!(
"{}{}",
".".repeat(level as usize),
// Bootstrap steps can be generic and thus contain angle brackets (<...>).
// However, Markdown interprets these as HTML, so we need to escap ethem.
step.r#type.replace('<', "&lt;").replace('>', "&gt;")
);
writeln!(output, "{label:.<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap();
}
output
}

View file

@ -58,11 +58,20 @@ version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "build_helper"
version = "0.1.0"
dependencies = [
"serde",
"serde_derive",
]
[[package]]
name = "citool"
version = "0.1.0"
dependencies = [
"anyhow",
"build_helper",
"clap",
"insta",
"serde",

View file

@ -10,6 +10,8 @@ serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
serde_json = "1"
build_helper = { path = "../../build_helper" }
[dev-dependencies]
insta = "1"

View file

@ -1,3 +1,5 @@
mod metrics;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::process::Command;
@ -6,6 +8,8 @@ use anyhow::Context;
use clap::Parser;
use serde_yaml::Value;
use crate::metrics::postprocess_metrics;
const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/..");
const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
const JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../github-actions/jobs.yml");
@ -338,6 +342,14 @@ enum Args {
#[clap(long = "type", default_value = "auto")]
job_type: JobType,
},
/// Postprocess the metrics.json file generated by bootstrap.
PostprocessMetrics {
/// Path to the metrics.json file
metrics_path: PathBuf,
/// Path to a file where the postprocessed metrics summary will be stored.
/// Usually, this will be GITHUB_STEP_SUMMARY on CI.
summary_path: PathBuf,
},
}
#[derive(clap::ValueEnum, Clone)]
@ -369,6 +381,9 @@ fn main() -> anyhow::Result<()> {
Args::RunJobLocally { job_type, name } => {
run_workflow_locally(load_db(default_jobs_file)?, job_type, name)?
}
Args::PostprocessMetrics { metrics_path, summary_path } => {
postprocess_metrics(&metrics_path, &summary_path)?;
}
}
Ok(())

View file

@ -0,0 +1,164 @@
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use anyhow::Context;
use build_helper::metrics::{
BuildStep, JsonNode, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps,
};
pub fn postprocess_metrics(metrics_path: &Path, summary_path: &Path) -> anyhow::Result<()> {
let metrics = load_metrics(metrics_path)?;
let mut file = File::options()
.append(true)
.create(true)
.open(summary_path)
.with_context(|| format!("Cannot open summary file at {summary_path:?}"))?;
if !metrics.invocations.is_empty() {
writeln!(file, "# Bootstrap steps")?;
record_bootstrap_step_durations(&metrics, &mut file)?;
record_test_suites(&metrics, &mut file)?;
}
Ok(())
}
fn record_bootstrap_step_durations(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> {
for invocation in &metrics.invocations {
let step = BuildStep::from_invocation(invocation);
let table = format_build_steps(&step);
eprintln!("Step `{}`\n{table}\n", invocation.cmdline);
writeln!(
file,
r"<details>
<summary>{}</summary>
<pre><code>{table}</code></pre>
</details>
",
invocation.cmdline
)?;
}
eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len());
Ok(())
}
fn record_test_suites(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> {
let suites = get_test_suites(&metrics);
if !suites.is_empty() {
let aggregated = aggregate_test_suites(&suites);
let table = render_table(aggregated);
writeln!(file, "\n# Test results\n")?;
writeln!(file, "{table}")?;
} else {
eprintln!("No test suites found in metrics");
}
Ok(())
}
fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
use std::fmt::Write;
let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string();
writeln!(table, "|:------|------:|------:|------:|").unwrap();
fn write_row(
buffer: &mut String,
name: &str,
record: &TestSuiteRecord,
surround: &str,
) -> std::fmt::Result {
let TestSuiteRecord { passed, ignored, failed } = record;
let total = (record.passed + record.ignored + record.failed) as f64;
let passed_pct = ((*passed as f64) / total) * 100.0;
let ignored_pct = ((*ignored as f64) / total) * 100.0;
let failed_pct = ((*failed as f64) / total) * 100.0;
write!(buffer, "| {surround}{name}{surround} |")?;
write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?;
write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?;
writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?;
Ok(())
}
let mut total = TestSuiteRecord::default();
for (name, record) in suites {
write_row(&mut table, &name, &record, "").unwrap();
total.passed += record.passed;
total.ignored += record.ignored;
total.failed += record.failed;
}
write_row(&mut table, "Total", &total, "**").unwrap();
table
}
#[derive(Default)]
struct TestSuiteRecord {
passed: u64,
ignored: u64,
failed: u64,
}
fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRecord> {
let mut records: BTreeMap<String, TestSuiteRecord> = BTreeMap::new();
for suite in suites {
let name = match &suite.metadata {
TestSuiteMetadata::CargoPackage { crates, stage, .. } => {
format!("{} (stage {stage})", crates.join(", "))
}
TestSuiteMetadata::Compiletest { suite, stage, .. } => {
format!("{suite} (stage {stage})")
}
};
let record = records.entry(name).or_default();
for test in &suite.tests {
match test.outcome {
TestOutcome::Passed => {
record.passed += 1;
}
TestOutcome::Failed => {
record.failed += 1;
}
TestOutcome::Ignored { .. } => {
record.ignored += 1;
}
}
}
}
records
}
fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> {
fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) {
for node in nodes {
match node {
JsonNode::RustbuildStep { children, .. } => {
visit_test_suites(&children, suites);
}
JsonNode::TestSuite(suite) => {
suites.push(&suite);
}
}
}
}
let mut suites = vec![];
for invocation in &metrics.invocations {
visit_test_suites(&invocation.children, &mut suites);
}
suites
}
fn load_metrics(path: &Path) -> anyhow::Result<JsonRoot> {
let metrics = std::fs::read_to_string(path)
.with_context(|| format!("Cannot read JSON metrics from {path:?}"))?;
let metrics: JsonRoot = serde_json::from_str(&metrics)
.with_context(|| format!("Cannot deserialize JSON metrics from {path:?}"))?;
Ok(metrics)
}

View file

@ -101,7 +101,7 @@ ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \
./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \
--host $HOSTS --target $HOSTS \
--include-default-paths \
build-manifest bootstrap
build-manifest bootstrap gcc
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
# This is the only builder which will create source tarballs

View file

@ -8,16 +8,10 @@ LINUX_VERSION=v6.14-rc3
../x.py build --stage 2 library rustdoc clippy rustfmt
../x.py build --stage 0 cargo
# Install rustup so that we can use the built toolchain easily, and also
# install bindgen in an easy way.
curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs
sh rustup.sh -y --default-toolchain none
BUILD_DIR=$(realpath ./build/x86_64-unknown-linux-gnu)
source /cargo/env
BUILD_DIR=$(realpath ./build)
rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage2
rustup default local
# Provide path to rustc, rustdoc, clippy-driver and rustfmt to RfL
export PATH=${PATH}:${BUILD_DIR}/stage2/bin
mkdir -p rfl
cd rfl
@ -33,10 +27,14 @@ git -C linux fetch --depth 1 origin ${LINUX_VERSION}
git -C linux checkout FETCH_HEAD
# Install bindgen
"${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage0/bin/cargo install \
"${BUILD_DIR}"/stage0/bin/cargo install \
--version $(linux/scripts/min-tool-version.sh bindgen) \
--root ${BUILD_DIR}/bindgen \
bindgen-cli
# Provide path to bindgen to RfL
export PATH=${PATH}:${BUILD_DIR}/bindgen/bin
# Configure Rust for Linux
cat <<EOF > linux/kernel/configs/rfl-for-rust-ci.config
# CONFIG_WERROR is not set

View file

@ -271,9 +271,8 @@ auto:
# Tests integration with Rust for Linux.
# Builds stage 1 compiler and tries to compile a few RfL examples with it.
# FIXME: fix rustup 1.28 issue
# - name: x86_64-rust-for-linux
# <<: *job-linux-4c
- name: x86_64-rust-for-linux
<<: *job-linux-4c
- name: x86_64-gnu
<<: *job-linux-4c

View file

@ -1,7 +1,7 @@
[package]
name = "rustdoc"
version = "0.0.0"
edition = "2021"
edition = "2024"
build = "build.rs"
[lib]

View file

@ -48,12 +48,12 @@ impl Cfg {
exclude: &FxHashSet<Cfg>,
) -> Result<Option<Cfg>, InvalidCfgError> {
match nested_cfg {
MetaItemInner::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude),
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b {
true => Ok(Some(Cfg::True)),
false => Ok(Some(Cfg::False)),
},
MetaItemInner::Lit(ref lit) => {
MetaItemInner::Lit(lit) => {
Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
}
}

View file

@ -741,7 +741,7 @@ pub(crate) fn clean_generics<'tcx>(
for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
let mut p = clean_generic_param(cx, Some(gens), p);
match &mut p.kind {
GenericParamDefKind::Lifetime { ref mut outlives } => {
GenericParamDefKind::Lifetime { outlives } => {
if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) {
// We merge bounds in the `where` clause.
for outlive in outlives.drain(..) {
@ -2688,7 +2688,7 @@ fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool {
/// Before calling this function, make sure `normal` is a `#[doc]` attribute.
fn filter_doc_attr(args: &mut hir::AttrArgs, is_inline: bool) {
match args {
hir::AttrArgs::Delimited(ref mut args) => {
hir::AttrArgs::Delimited(args) => {
let tokens = filter_tokens_from_list(&args.tokens, |token| {
!matches!(
token,

View file

@ -502,7 +502,7 @@ impl Item {
let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] };
links
.iter()
.filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| {
.filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
debug!(?id);
if let Ok((mut href, ..)) = href(*id, cx) {
debug!(?href);
@ -1150,7 +1150,7 @@ pub(crate) struct Attributes {
}
impl Attributes {
pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> + '_ {
pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
hir_attr_lists(&self.other_attrs[..], name)
}
@ -1864,7 +1864,7 @@ impl PrimitiveType {
.copied()
}
pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> + '_ {
pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
Self::simplified_types()
.values()
.flatten()
@ -2259,7 +2259,7 @@ impl GenericArgs {
GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
}
}
pub(crate) fn constraints<'a>(&'a self) -> Box<dyn Iterator<Item = AssocItemConstraint> + 'a> {
pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
match self {
GenericArgs::AngleBracketed { constraints, .. } => {
Box::new(constraints.iter().cloned())

View file

@ -60,7 +60,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
let primitives = local_crate.primitives(cx.tcx);
let keywords = local_crate.keywords(cx.tcx);
{
let ItemKind::ModuleItem(ref mut m) = &mut module.inner.kind else { unreachable!() };
let ItemKind::ModuleItem(m) = &mut module.inner.kind else { unreachable!() };
m.items.extend(primitives.iter().map(|&(def_id, prim)| {
Item::from_def_id_and_parts(
def_id,
@ -302,7 +302,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
use rustc_hir::*;
debug!("trying to get a name from pattern: {p:?}");
Symbol::intern(&match p.kind {
Symbol::intern(&match &p.kind {
// FIXME(never_patterns): does this make sense?
PatKind::Wild
| PatKind::Err(_)
@ -313,8 +313,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
}
PatKind::Binding(_, _, ident, _) => return ident.name,
PatKind::Box(p) | PatKind::Ref(p, _) | PatKind::Guard(p, _) => return name_from_pat(p),
PatKind::TupleStruct(ref p, ..)
| PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p),
PatKind::TupleStruct(p, ..) | PatKind::Expr(PatExpr { kind: PatExprKind::Path(p), .. }) => {
qpath_to_string(p)
}
PatKind::Or(pats) => {
fmt::from_fn(|f| pats.iter().map(|p| name_from_pat(p)).joined(" | ", f)).to_string()
}
@ -329,7 +330,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
return Symbol::intern("()");
}
PatKind::Slice(begin, mid, end) => {
fn print_pat<'a>(pat: &'a Pat<'a>, wild: bool) -> impl Display + 'a {
fn print_pat(pat: &Pat<'_>, wild: bool) -> impl Display {
fmt::from_fn(move |f| {
if wild {
f.write_str("..")?;
@ -493,7 +494,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
pub(crate) fn synthesize_auto_trait_and_blanket_impls(
cx: &mut DocContext<'_>,
item_def_id: DefId,
) -> impl Iterator<Item = Item> {
) -> impl Iterator<Item = Item> + use<> {
let auto_impls = cx
.sess()
.prof

View file

@ -15,7 +15,6 @@ use std::iter::{self, once};
use itertools::Either;
use rustc_abi::ExternAbi;
use rustc_attr_parsing::{ConstStability, StabilityLevel, StableSince};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@ -41,10 +40,10 @@ pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) {
s.write_fmt(f).unwrap();
}
pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
bounds: &'a [clean::GenericBound],
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print_generic_bounds(
bounds: &[clean::GenericBound],
cx: &Context<'_>,
) -> impl Display {
fmt::from_fn(move |f| {
let mut bounds_dup = FxHashSet::default();
@ -57,10 +56,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
}
impl clean::GenericParamDef {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match &self.kind {
clean::GenericParamDefKind::Lifetime { outlives } => {
write!(f, "{}", self.name)?;
@ -80,7 +76,7 @@ impl clean::GenericParamDef {
print_generic_bounds(bounds, cx).fmt(f)?;
}
if let Some(ref ty) = default {
if let Some(ty) = default {
f.write_str(" = ")?;
ty.print(cx).fmt(f)?;
}
@ -107,10 +103,7 @@ impl clean::GenericParamDef {
}
impl clean::Generics {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
if real_params.peek().is_none() {
@ -134,10 +127,7 @@ pub(crate) enum Ending {
NoNewline,
}
fn print_where_predicate<'a, 'tcx: 'a>(
predicate: &'a clean::WherePredicate,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
match predicate {
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
@ -173,12 +163,12 @@ fn print_where_predicate<'a, 'tcx: 'a>(
/// * The Generics from which to emit a where-clause.
/// * The number of spaces to indent each line with.
/// * Whether the where-clause needs to add a comma and newline after the last bound.
pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
gens: &'a clean::Generics,
cx: &'a Context<'tcx>,
pub(crate) fn print_where_clause(
gens: &clean::Generics,
cx: &Context<'_>,
indent: usize,
ending: Ending,
) -> Option<impl Display + 'a + Captures<'tcx>> {
) -> Option<impl Display> {
if gens.where_predicates.is_empty() {
return None;
}
@ -250,13 +240,13 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
}
impl clean::Lifetime {
pub(crate) fn print(&self) -> impl Display + '_ {
pub(crate) fn print(&self) -> impl Display {
self.0.as_str()
}
}
impl clean::ConstantKind {
pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ {
pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display {
let expr = self.expr(tcx);
fmt::from_fn(move |f| {
if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
@ -265,7 +255,7 @@ impl clean::ConstantKind {
}
impl clean::PolyTrait {
fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?;
self.trait_.print(cx).fmt(f)
@ -274,10 +264,7 @@ impl clean::PolyTrait {
}
impl clean::GenericBound {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match self {
clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
clean::GenericBound::TraitBound(ty, modifiers) => {
@ -304,7 +291,7 @@ impl clean::GenericBound {
}
impl clean::GenericArgs {
fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
match self {
clean::GenericArgs::AngleBracketed { args, constraints } => {
@ -809,11 +796,11 @@ fn primitive_link_fragment(
Ok(())
}
fn tybounds<'a, 'tcx: 'a>(
bounds: &'a [clean::PolyTrait],
lt: &'a Option<clean::Lifetime>,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
fn tybounds(
bounds: &[clean::PolyTrait],
lt: &Option<clean::Lifetime>,
cx: &Context<'_>,
) -> impl Display {
fmt::from_fn(move |f| {
bounds.iter().map(|bound| bound.print(cx)).joined(" + ", f)?;
if let Some(lt) = lt {
@ -825,11 +812,11 @@ fn tybounds<'a, 'tcx: 'a>(
})
}
fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
params: &'a [clean::GenericParamDef],
cx: &'a Context<'tcx>,
fn print_higher_ranked_params_with_space(
params: &[clean::GenericParamDef],
cx: &Context<'_>,
keyword: &'static str,
) -> impl Display + 'a + Captures<'tcx> {
) -> impl Display {
fmt::from_fn(move |f| {
if !params.is_empty() {
f.write_str(keyword)?;
@ -841,11 +828,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
})
}
pub(crate) fn anchor<'a: 'cx, 'cx>(
did: DefId,
text: Symbol,
cx: &'cx Context<'a>,
) -> impl Display + Captures<'a> + 'cx {
pub(crate) fn anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
let parts = href(did, cx);
if let Ok((url, short_ty, fqp)) = parts {
@ -1121,29 +1104,19 @@ fn fmt_type(
}
impl clean::Type {
pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'b + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| fmt_type(self, f, false, cx))
}
}
impl clean::Path {
pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'b + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
}
}
impl clean::Impl {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
use_absolute: bool,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, use_absolute: bool, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
f.write_str("impl")?;
self.generics.print(cx).fmt(f)?;
@ -1182,12 +1155,12 @@ impl clean::Impl {
print_where_clause(&self.generics, cx, 0, Ending::Newline).maybe_display().fmt(f)
})
}
fn print_type<'a, 'tcx: 'a>(
fn print_type(
&self,
type_: &clean::Type,
f: &mut fmt::Formatter<'_>,
use_absolute: bool,
cx: &'a Context<'tcx>,
cx: &Context<'_>,
) -> Result<(), fmt::Error> {
if let clean::Type::Tuple(types) = type_
&& let [clean::Type::Generic(name)] = &types[..]
@ -1258,10 +1231,7 @@ impl clean::Impl {
}
impl clean::Arguments {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
self.values
.iter()
@ -1301,10 +1271,7 @@ impl Display for Indent {
}
impl clean::FnDecl {
pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'b + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
let ellipsis = if self.c_variadic { ", ..." } else { "" };
if f.alternate() {
@ -1333,12 +1300,12 @@ impl clean::FnDecl {
/// are preserved.
/// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
/// necessary.
pub(crate) fn full_print<'a, 'tcx: 'a>(
&'a self,
pub(crate) fn full_print(
&self,
header_len: usize,
indent: usize,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
cx: &Context<'_>,
) -> impl Display {
fmt::from_fn(move |f| {
// First, generate the text form of the declaration, with no line wrapping, and count the bytes.
let mut counter = WriteCounter(0);
@ -1420,10 +1387,7 @@ impl clean::FnDecl {
self.print_output(cx).fmt(f)
}
fn print_output<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
fn print_output(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match &self.output {
clean::Tuple(tys) if tys.is_empty() => Ok(()),
ty if f.alternate() => {
@ -1434,10 +1398,7 @@ impl clean::FnDecl {
}
}
pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
item: &clean::Item,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>) -> impl Display {
use std::fmt::Write as _;
let vis: Cow<'static, str> = match item.visibility(cx.tcx()) {
None => "".into(),
@ -1546,10 +1507,7 @@ pub(crate) fn print_constness_with_space(
}
impl clean::Import {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match self.kind {
clean::ImportKind::Simple(name) => {
if name == self.source.path.last() {
@ -1570,10 +1528,7 @@ impl clean::Import {
}
impl clean::ImportSource {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match self.did {
Some(did) => resolved_path(f, did, &self.path, true, false, cx),
_ => {
@ -1593,10 +1548,7 @@ impl clean::ImportSource {
}
impl clean::AssocItemConstraint {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
f.write_str(self.assoc.name.as_str())?;
self.assoc.args.print(cx).fmt(f)?;
@ -1627,15 +1579,12 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
})
}
pub(crate) fn print_default_space<'a>(v: bool) -> &'a str {
pub(crate) fn print_default_space(v: bool) -> &'static str {
if v { "default " } else { "" }
}
impl clean::GenericArg {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match self {
clean::GenericArg::Lifetime(lt) => lt.print().fmt(f),
clean::GenericArg::Type(ty) => ty.print(cx).fmt(f),
@ -1646,10 +1595,7 @@ impl clean::GenericArg {
}
impl clean::Term {
pub(crate) fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| match self {
clean::Term::Type(ty) => ty.print(cx).fmt(f),
clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f),

View file

@ -47,7 +47,6 @@ use rinja::Template;
use rustc_attr_parsing::{
ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince,
};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir::Mutability;
use rustc_hir::def_id::{DefId, DefIdSet};
@ -82,7 +81,7 @@ use crate::html::{highlight, sources};
use crate::scrape_examples::{CallData, CallLocation};
use crate::{DOC_RUST_LANG_ORG_VERSION, try_none};
pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display {
fmt::from_fn(move |f| {
if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) }
})
@ -310,7 +309,7 @@ impl ItemEntry {
}
impl ItemEntry {
pub(crate) fn print(&self) -> impl fmt::Display + '_ {
pub(crate) fn print(&self) -> impl fmt::Display {
fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)))
}
}
@ -505,12 +504,12 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
)
}
fn document<'a, 'cx: 'a>(
cx: &'a Context<'cx>,
item: &'a clean::Item,
parent: Option<&'a clean::Item>,
fn document(
cx: &Context<'_>,
item: &clean::Item,
parent: Option<&clean::Item>,
heading_offset: HeadingOffset,
) -> impl fmt::Display + 'a + Captures<'cx> {
) -> impl fmt::Display {
if let Some(ref name) = item.name {
info!("Documenting {name}");
}
@ -526,12 +525,12 @@ fn document<'a, 'cx: 'a>(
}
/// Render md_text as markdown.
fn render_markdown<'a, 'cx: 'a>(
cx: &'a Context<'cx>,
md_text: &'a str,
fn render_markdown(
cx: &Context<'_>,
md_text: &str,
links: Vec<RenderedLink>,
heading_offset: HeadingOffset,
) -> impl fmt::Display + 'a + Captures<'cx> {
) -> impl fmt::Display {
fmt::from_fn(move |f| {
write!(
f,
@ -552,13 +551,13 @@ fn render_markdown<'a, 'cx: 'a>(
/// Writes a documentation block containing only the first paragraph of the documentation. If the
/// docs are longer, a "Read more" link is appended to the end.
fn document_short<'a, 'cx: 'a>(
item: &'a clean::Item,
cx: &'a Context<'cx>,
link: AssocItemLink<'a>,
parent: &'a clean::Item,
fn document_short(
item: &clean::Item,
cx: &Context<'_>,
link: AssocItemLink<'_>,
parent: &clean::Item,
show_def_docs: bool,
) -> impl fmt::Display + 'a + Captures<'cx> {
) -> impl fmt::Display {
fmt::from_fn(move |f| {
document_item_info(cx, item, Some(parent)).render_into(f).unwrap();
if !show_def_docs {
@ -595,28 +594,28 @@ fn document_short<'a, 'cx: 'a>(
})
}
fn document_full_collapsible<'a, 'cx: 'a>(
item: &'a clean::Item,
cx: &'a Context<'cx>,
fn document_full_collapsible(
item: &clean::Item,
cx: &Context<'_>,
heading_offset: HeadingOffset,
) -> impl fmt::Display + 'a + Captures<'cx> {
) -> impl fmt::Display {
document_full_inner(item, cx, true, heading_offset)
}
fn document_full<'a, 'cx: 'a>(
item: &'a clean::Item,
cx: &'a Context<'cx>,
fn document_full(
item: &clean::Item,
cx: &Context<'_>,
heading_offset: HeadingOffset,
) -> impl fmt::Display + 'a + Captures<'cx> {
) -> impl fmt::Display {
document_full_inner(item, cx, false, heading_offset)
}
fn document_full_inner<'a, 'cx: 'a>(
item: &'a clean::Item,
cx: &'a Context<'cx>,
fn document_full_inner(
item: &clean::Item,
cx: &Context<'_>,
is_collapsible: bool,
heading_offset: HeadingOffset,
) -> impl fmt::Display + 'a + Captures<'cx> {
) -> impl fmt::Display {
fmt::from_fn(move |f| {
if let Some(s) = item.opt_doc_value() {
debug!("Doc block: =====\n{s}\n=====");
@ -797,11 +796,11 @@ pub(crate) fn render_impls(
}
/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
fn assoc_href_attr<'a, 'tcx>(
fn assoc_href_attr(
it: &clean::Item,
link: AssocItemLink<'a>,
cx: &Context<'tcx>,
) -> Option<impl fmt::Display + 'a + Captures<'tcx>> {
link: AssocItemLink<'_>,
cx: &Context<'_>,
) -> Option<impl fmt::Display> {
let name = it.name.unwrap();
let item_type = it.type_();
@ -812,7 +811,7 @@ fn assoc_href_attr<'a, 'tcx>(
}
let href = match link {
AssocItemLink::Anchor(Some(ref id)) => Href::AnchorId(id),
AssocItemLink::Anchor(Some(id)) => Href::AnchorId(id),
AssocItemLink::Anchor(None) => Href::Anchor(item_type),
AssocItemLink::GotoSource(did, provided_methods) => {
// We're creating a link from the implementation of an associated item to its
@ -877,15 +876,15 @@ enum AssocConstValue<'a> {
None,
}
fn assoc_const<'a, 'tcx>(
it: &'a clean::Item,
generics: &'a clean::Generics,
ty: &'a clean::Type,
value: AssocConstValue<'a>,
link: AssocItemLink<'a>,
fn assoc_const(
it: &clean::Item,
generics: &clean::Generics,
ty: &clean::Type,
value: AssocConstValue<'_>,
link: AssocItemLink<'_>,
indent: usize,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
cx: &Context<'_>,
) -> impl fmt::Display {
let tcx = cx.tcx();
fmt::from_fn(move |w| {
write!(
@ -917,15 +916,15 @@ fn assoc_const<'a, 'tcx>(
})
}
fn assoc_type<'a, 'tcx>(
it: &'a clean::Item,
generics: &'a clean::Generics,
bounds: &'a [clean::GenericBound],
default: Option<&'a clean::Type>,
link: AssocItemLink<'a>,
fn assoc_type(
it: &clean::Item,
generics: &clean::Generics,
bounds: &[clean::GenericBound],
default: Option<&clean::Type>,
link: AssocItemLink<'_>,
indent: usize,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
cx: &Context<'_>,
) -> impl fmt::Display {
fmt::from_fn(move |w| {
write!(
w,
@ -947,15 +946,15 @@ fn assoc_type<'a, 'tcx>(
})
}
fn assoc_method<'a, 'tcx>(
meth: &'a clean::Item,
g: &'a clean::Generics,
d: &'a clean::FnDecl,
link: AssocItemLink<'a>,
fn assoc_method(
meth: &clean::Item,
g: &clean::Generics,
d: &clean::FnDecl,
link: AssocItemLink<'_>,
parent: ItemType,
cx: &'a Context<'tcx>,
cx: &Context<'_>,
render_mode: RenderMode,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
let tcx = cx.tcx();
let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
let name = meth.name.as_ref().unwrap();
@ -1031,7 +1030,7 @@ fn render_stability_since_raw_with_extra(
stable_version: Option<StableSince>,
const_stability: Option<ConstStability>,
extra_class: &str,
) -> Option<impl fmt::Display + '_> {
) -> Option<impl fmt::Display> {
let mut title = String::new();
let mut stability = String::new();
@ -1102,13 +1101,13 @@ fn render_stability_since_raw(
render_stability_since_raw_with_extra(ver, const_stability, "")
}
fn render_assoc_item<'a, 'tcx>(
item: &'a clean::Item,
link: AssocItemLink<'a>,
fn render_assoc_item(
item: &clean::Item,
link: AssocItemLink<'_>,
parent: ItemType,
cx: &'a Context<'tcx>,
cx: &Context<'_>,
render_mode: RenderMode,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
fmt::from_fn(move |f| match &item.kind {
clean::StrippedItem(..) => Ok(()),
clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => {
@ -1144,7 +1143,7 @@ fn render_assoc_item<'a, 'tcx>(
cx,
)
.fmt(f),
clean::RequiredAssocTypeItem(ref generics, ref bounds) => assoc_type(
clean::RequiredAssocTypeItem(generics, bounds) => assoc_type(
item,
generics,
bounds,
@ -1154,7 +1153,7 @@ fn render_assoc_item<'a, 'tcx>(
cx,
)
.fmt(f),
clean::AssocTypeItem(ref ty, ref bounds) => assoc_type(
clean::AssocTypeItem(ty, bounds) => assoc_type(
item,
&ty.generics,
bounds,
@ -1170,11 +1169,7 @@ fn render_assoc_item<'a, 'tcx>(
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
// a whitespace prefix and newline.
fn render_attributes_in_pre<'a, 'tcx: 'a>(
it: &'a clean::Item,
prefix: &'a str,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
fmt::from_fn(move |f| {
for a in it.attributes(cx.tcx(), cx.cache(), false) {
writeln!(f, "{prefix}{a}")?;
@ -1206,12 +1201,12 @@ impl<'a> AssocItemLink<'a> {
}
}
pub fn write_section_heading<'a>(
title: &'a str,
id: &'a str,
extra_class: Option<&'a str>,
extra: impl fmt::Display + 'a,
) -> impl fmt::Display + 'a {
pub fn write_section_heading(
title: &str,
id: &str,
extra_class: Option<&str>,
extra: impl fmt::Display,
) -> impl fmt::Display {
fmt::from_fn(move |w| {
let (extra_class, whitespace) = match extra_class {
Some(extra) => (extra, " "),
@ -1227,7 +1222,7 @@ pub fn write_section_heading<'a>(
})
}
fn write_impl_section_heading<'a>(title: &'a str, id: &'a str) -> impl fmt::Display + 'a {
fn write_impl_section_heading(title: &str, id: &str) -> impl fmt::Display {
write_section_heading(title, id, None, "")
}
@ -1276,12 +1271,12 @@ pub(crate) fn render_all_impls(
}
}
fn render_assoc_items<'a, 'cx: 'a>(
cx: &'a Context<'cx>,
containing_item: &'a clean::Item,
fn render_assoc_items(
cx: &Context<'_>,
containing_item: &clean::Item,
it: DefId,
what: AssocItemRender<'a>,
) -> impl fmt::Display + 'a + Captures<'cx> {
what: AssocItemRender<'_>,
) -> impl fmt::Display {
fmt::from_fn(move |f| {
let mut derefs = DefIdSet::default();
derefs.insert(it);
@ -1466,10 +1461,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
}
}
pub(crate) fn notable_traits_button<'a, 'tcx>(
ty: &'a clean::Type,
cx: &'a Context<'tcx>,
) -> Option<impl fmt::Display + 'a + Captures<'tcx>> {
pub(crate) fn notable_traits_button(
ty: &clean::Type,
cx: &Context<'_>,
) -> Option<impl fmt::Display> {
let mut has_notable_trait = false;
if ty.is_unit() {
@ -1623,16 +1618,16 @@ struct ImplRenderingParameters {
toggle_open_by_default: bool,
}
fn render_impl<'a, 'tcx>(
cx: &'a Context<'tcx>,
i: &'a Impl,
parent: &'a clean::Item,
link: AssocItemLink<'a>,
fn render_impl(
cx: &Context<'_>,
i: &Impl,
parent: &clean::Item,
link: AssocItemLink<'_>,
render_mode: RenderMode,
use_absolute: Option<bool>,
aliases: &'a [String],
aliases: &[String],
rendering_params: ImplRenderingParameters,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
fmt::from_fn(move |w| {
let cache = &cx.shared.cache;
let traits = &cache.traits;
@ -1780,7 +1775,7 @@ fn render_impl<'a, 'tcx>(
);
}
}
clean::RequiredAssocConstItem(ref generics, ref ty) => {
clean::RequiredAssocConstItem(generics, ty) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
write_str(
@ -1847,7 +1842,7 @@ fn render_impl<'a, 'tcx>(
),
);
}
clean::RequiredAssocTypeItem(ref generics, ref bounds) => {
clean::RequiredAssocTypeItem(generics, bounds) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
write_str(
@ -2135,11 +2130,11 @@ fn render_impl<'a, 'tcx>(
// Render the items that appear on the right side of methods, impls, and
// associated types. For example "1.0.0 (const: 1.39.0) · source".
fn render_rightside<'a, 'tcx>(
cx: &'a Context<'tcx>,
item: &'a clean::Item,
fn render_rightside(
cx: &Context<'_>,
item: &clean::Item,
render_mode: RenderMode,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
let tcx = cx.tcx();
fmt::from_fn(move |w| {
@ -2174,17 +2169,17 @@ fn render_rightside<'a, 'tcx>(
})
}
pub(crate) fn render_impl_summary<'a, 'tcx>(
cx: &'a Context<'tcx>,
i: &'a Impl,
parent: &'a clean::Item,
pub(crate) fn render_impl_summary(
cx: &Context<'_>,
i: &Impl,
parent: &clean::Item,
show_def_docs: bool,
use_absolute: Option<bool>,
// This argument is used to reference same type with different paths to avoid duplication
// in documentation pages for trait with automatic implementations like "Send" and "Sync".
aliases: &'a [String],
doc: Option<&'a str>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
aliases: &[String],
doc: Option<&str>,
) -> impl fmt::Display {
fmt::from_fn(move |w| {
let inner_impl = i.inner_impl();
let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));

View file

@ -4,7 +4,6 @@ use std::fmt::{Display, Write as _};
use rinja::Template;
use rustc_abi::VariantIdx;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
@ -92,44 +91,32 @@ macro_rules! item_template {
macro_rules! item_template_methods {
() => {};
(document $($rest:tt)*) => {
fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
fmt::from_fn(move |f| {
let (item, cx) = self.item_and_cx();
let v = document(cx, item, None, HeadingOffset::H2);
write!(f, "{v}")
})
fn document(&self) -> impl fmt::Display {
let (item, cx) = self.item_and_cx();
document(cx, item, None, HeadingOffset::H2)
}
item_template_methods!($($rest)*);
};
(document_type_layout $($rest:tt)*) => {
fn document_type_layout<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
fmt::from_fn(move |f| {
let (item, cx) = self.item_and_cx();
let def_id = item.item_id.expect_def_id();
let v = document_type_layout(cx, def_id);
write!(f, "{v}")
})
fn document_type_layout(&self) -> impl fmt::Display {
let (item, cx) = self.item_and_cx();
let def_id = item.item_id.expect_def_id();
document_type_layout(cx, def_id)
}
item_template_methods!($($rest)*);
};
(render_attributes_in_pre $($rest:tt)*) => {
fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
fmt::from_fn(move |f| {
let (item, cx) = self.item_and_cx();
let v = render_attributes_in_pre(item, "", cx);
write!(f, "{v}")
})
fn render_attributes_in_pre(&self) -> impl fmt::Display {
let (item, cx) = self.item_and_cx();
render_attributes_in_pre(item, "", cx)
}
item_template_methods!($($rest)*);
};
(render_assoc_items $($rest:tt)*) => {
fn render_assoc_items<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
fmt::from_fn(move |f| {
let (item, cx) = self.item_and_cx();
let def_id = item.item_id.expect_def_id();
let v = render_assoc_items(cx, item, def_id, AssocItemRender::All);
write!(f, "{v}")
})
fn render_assoc_items(&self) -> impl fmt::Display {
let (item, cx) = self.item_and_cx();
let def_id = item.item_id.expect_def_id();
render_assoc_items(cx, item, def_id, AssocItemRender::All)
}
item_template_methods!($($rest)*);
};
@ -162,10 +149,7 @@ struct ItemVars<'a> {
src_href: Option<&'a str>,
}
pub(super) fn print_item<'a, 'tcx>(
cx: &'a Context<'tcx>,
item: &'a clean::Item,
) -> impl fmt::Display + 'a + Captures<'tcx> {
pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Display {
debug_assert!(!item.is_stripped());
fmt::from_fn(|buf| {
@ -241,30 +225,30 @@ pub(super) fn print_item<'a, 'tcx>(
item_vars.render_into(buf).unwrap();
match &item.kind {
clean::ModuleItem(ref m) => {
clean::ModuleItem(m) => {
write!(buf, "{}", item_module(cx, item, &m.items))
}
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
clean::FunctionItem(f) | clean::ForeignFunctionItem(f, _) => {
write!(buf, "{}", item_function(cx, item, f))
}
clean::TraitItem(ref t) => write!(buf, "{}", item_trait(cx, item, t)),
clean::StructItem(ref s) => {
clean::TraitItem(t) => write!(buf, "{}", item_trait(cx, item, t)),
clean::StructItem(s) => {
write!(buf, "{}", item_struct(cx, item, s))
}
clean::UnionItem(ref s) => write!(buf, "{}", item_union(cx, item, s)),
clean::EnumItem(ref e) => write!(buf, "{}", item_enum(cx, item, e)),
clean::TypeAliasItem(ref t) => {
clean::UnionItem(s) => write!(buf, "{}", item_union(cx, item, s)),
clean::EnumItem(e) => write!(buf, "{}", item_enum(cx, item, e)),
clean::TypeAliasItem(t) => {
write!(buf, "{}", item_type_alias(cx, item, t))
}
clean::MacroItem(ref m) => write!(buf, "{}", item_macro(cx, item, m)),
clean::ProcMacroItem(ref m) => {
clean::MacroItem(m) => write!(buf, "{}", item_macro(cx, item, m)),
clean::ProcMacroItem(m) => {
write!(buf, "{}", item_proc_macro(cx, item, m))
}
clean::PrimitiveItem(_) => write!(buf, "{}", item_primitive(cx, item)),
clean::StaticItem(ref i) => {
clean::StaticItem(i) => {
write!(buf, "{}", item_static(cx, item, i, None))
}
clean::ForeignStaticItem(ref i, safety) => {
clean::ForeignStaticItem(i, safety) => {
write!(buf, "{}", item_static(cx, item, i, Some(*safety)))
}
clean::ConstantItem(ci) => {
@ -274,7 +258,7 @@ pub(super) fn print_item<'a, 'tcx>(
write!(buf, "{}", item_foreign_type(cx, item))
}
clean::KeywordItem => write!(buf, "{}", item_keyword(cx, item)),
clean::TraitAliasItem(ref ta) => {
clean::TraitAliasItem(ta) => {
write!(buf, "{}", item_trait_alias(cx, item, ta))
}
_ => {
@ -321,11 +305,7 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display {
fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>);
}
fn item_module<'a, 'tcx>(
cx: &'a Context<'tcx>,
item: &'a clean::Item,
items: &'a [clean::Item],
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> impl fmt::Display {
fmt::from_fn(|w| {
write!(w, "{}", document(cx, item, None, HeadingOffset::H2))?;
@ -541,14 +521,14 @@ fn item_module<'a, 'tcx>(
/// Render the stability, deprecation and portability tags that are displayed in the item's summary
/// at the module level.
fn extra_info_tags<'a, 'tcx: 'a>(
tcx: TyCtxt<'tcx>,
item: &'a clean::Item,
parent: &'a clean::Item,
fn extra_info_tags(
tcx: TyCtxt<'_>,
item: &clean::Item,
parent: &clean::Item,
import_def_id: Option<DefId>,
) -> impl Display + 'a + Captures<'tcx> {
) -> impl Display {
fmt::from_fn(move |f| {
fn tag_html<'a>(class: &'a str, title: &'a str, contents: &'a str) -> impl Display + 'a {
fn tag_html(class: &str, title: &str, contents: &str) -> impl Display {
fmt::from_fn(move |f| {
write!(
f,
@ -597,11 +577,7 @@ fn extra_info_tags<'a, 'tcx: 'a>(
})
}
fn item_function<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
f: &'a clean::Function,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> impl fmt::Display {
fmt::from_fn(|w| {
let tcx = cx.tcx();
let header = it.fn_header(tcx).expect("printing a function which isn't a function");
@ -657,11 +633,7 @@ fn item_function<'a, 'tcx>(
})
}
fn item_trait<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
t: &'a clean::Trait,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt::Display {
fmt::from_fn(|w| {
let tcx = cx.tcx();
let bounds = bounds(&t.bounds, false, cx);
@ -831,11 +803,7 @@ fn item_trait<'a, 'tcx>(
// Trait documentation
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
fn trait_item<'a, 'tcx>(
cx: &'a Context<'tcx>,
m: &'a clean::Item,
t: &'a clean::Item,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn trait_item(cx: &Context<'_>, m: &clean::Item, t: &clean::Item) -> impl fmt::Display {
fmt::from_fn(|w| {
let name = m.name.unwrap();
info!("Documenting {name} on {ty_name:?}", ty_name = t.name);
@ -1021,7 +989,7 @@ fn item_trait<'a, 'tcx>(
extern_crates.insert(did.krate);
}
match implementor.inner_impl().for_.without_borrowed_ref() {
clean::Type::Path { ref path } if !path.is_assoc_ty() => {
clean::Type::Path { path } if !path.is_assoc_ty() => {
let did = path.def_id();
let &mut (prev_did, ref mut has_duplicates) =
implementor_dups.entry(path.last()).or_insert((did, false));
@ -1254,11 +1222,11 @@ fn item_trait<'a, 'tcx>(
})
}
fn item_trait_alias<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
t: &'a clean::TraitAlias,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_trait_alias(
cx: &Context<'_>,
it: &clean::Item,
t: &clean::TraitAlias,
) -> impl fmt::Display {
fmt::from_fn(|w| {
wrap_item(w, |w| {
write!(
@ -1285,11 +1253,7 @@ fn item_trait_alias<'a, 'tcx>(
})
}
fn item_type_alias<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
t: &'a clean::TypeAlias,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> impl fmt::Display {
fmt::from_fn(|w| {
wrap_item(w, |w| {
write!(
@ -1499,11 +1463,7 @@ fn item_type_alias<'a, 'tcx>(
})
}
fn item_union<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
s: &'a clean::Union,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display {
item_template!(
#[template(path = "item_union.html")]
struct ItemUnion<'a, 'cx> {
@ -1515,35 +1475,20 @@ fn item_union<'a, 'tcx>(
);
impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
fn render_union<'b>(&'b self) -> impl Display + Captures<'a> + 'b + Captures<'cx> {
fmt::from_fn(move |f| {
let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx);
write!(f, "{v}")
})
fn render_union(&self) -> impl Display {
render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx)
}
fn document_field<'b>(
&'b self,
field: &'a clean::Item,
) -> impl Display + Captures<'a> + 'b + Captures<'cx> {
fmt::from_fn(move |f| {
let v = document(self.cx, field, Some(self.it), HeadingOffset::H3);
write!(f, "{v}")
})
fn document_field(&self, field: &'a clean::Item) -> impl Display {
document(self.cx, field, Some(self.it), HeadingOffset::H3)
}
fn stability_field(&self, field: &clean::Item) -> Option<String> {
field.stability_class(self.cx.tcx())
}
fn print_ty<'b>(
&'b self,
ty: &'a clean::Type,
) -> impl Display + Captures<'a> + 'b + Captures<'cx> {
fmt::from_fn(move |f| {
let v = ty.print(self.cx);
write!(f, "{v}")
})
fn print_ty(&self, ty: &'a clean::Type) -> impl Display {
ty.print(self.cx)
}
fn fields_iter(
@ -1566,10 +1511,7 @@ fn item_union<'a, 'tcx>(
})
}
fn print_tuple_struct_fields<'a, 'cx: 'a>(
cx: &'a Context<'cx>,
s: &'a [clean::Item],
) -> impl Display + 'a + Captures<'cx> {
fn print_tuple_struct_fields(cx: &Context<'_>, s: &[clean::Item]) -> impl Display {
fmt::from_fn(|f| {
if !s.is_empty()
&& s.iter().all(|field| {
@ -1591,11 +1533,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
})
}
fn item_enum<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
e: &'a clean::Enum,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display {
fmt::from_fn(|w| {
let count_variants = e.variants().count();
wrap_item(w, |w| {
@ -1658,14 +1596,14 @@ fn should_show_enum_discriminant(
repr.c() || repr.int.is_some()
}
fn display_c_like_variant<'a, 'tcx>(
cx: &'a Context<'tcx>,
item: &'a clean::Item,
variant: &'a clean::Variant,
fn display_c_like_variant(
cx: &Context<'_>,
item: &clean::Item,
variant: &clean::Variant,
index: VariantIdx,
should_show_enum_discriminant: bool,
enum_def_id: DefId,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
fmt::from_fn(move |w| {
let name = item.name.unwrap();
if let Some(ref value) = variant.discriminant {
@ -1685,15 +1623,15 @@ fn display_c_like_variant<'a, 'tcx>(
})
}
fn render_enum_fields<'a, 'tcx>(
cx: &'a Context<'tcx>,
g: Option<&'a clean::Generics>,
variants: &'a IndexVec<VariantIdx, clean::Item>,
fn render_enum_fields(
cx: &Context<'_>,
g: Option<&clean::Generics>,
variants: &IndexVec<VariantIdx, clean::Item>,
count_variants: usize,
has_stripped_entries: bool,
is_non_exhaustive: bool,
enum_def_id: DefId,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
fmt::from_fn(move |w| {
let should_show_enum_discriminant =
should_show_enum_discriminant(cx, enum_def_id, variants);
@ -1764,12 +1702,12 @@ fn render_enum_fields<'a, 'tcx>(
})
}
fn item_variants<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
variants: &'a IndexVec<VariantIdx, clean::Item>,
fn item_variants(
cx: &Context<'_>,
it: &clean::Item,
variants: &IndexVec<VariantIdx, clean::Item>,
enum_def_id: DefId,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
fmt::from_fn(move |w| {
let tcx = cx.tcx();
write!(
@ -1895,11 +1833,7 @@ fn item_variants<'a, 'tcx>(
})
}
fn item_macro<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
t: &'a clean::Macro,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_macro(cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) -> impl fmt::Display {
fmt::from_fn(|w| {
wrap_item(w, |w| {
// FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
@ -1912,11 +1846,7 @@ fn item_macro<'a, 'tcx>(
})
}
fn item_proc_macro<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
m: &'a clean::ProcMacro,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_proc_macro(cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) -> impl fmt::Display {
fmt::from_fn(|w| {
wrap_item(w, |w| {
let name = it.name.expect("proc-macros always have names");
@ -1947,10 +1877,7 @@ fn item_proc_macro<'a, 'tcx>(
})
}
fn item_primitive<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_primitive(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
fmt::from_fn(|w| {
let def_id = it.item_id.expect_def_id();
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
@ -1968,13 +1895,13 @@ fn item_primitive<'a, 'tcx>(
})
}
fn item_constant<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
generics: &'a clean::Generics,
ty: &'a clean::Type,
c: &'a clean::ConstantKind,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_constant(
cx: &Context<'_>,
it: &clean::Item,
generics: &clean::Generics,
ty: &clean::Type,
c: &clean::ConstantKind,
) -> impl fmt::Display {
fmt::from_fn(|w| {
wrap_item(w, |w| {
let tcx = cx.tcx();
@ -2028,11 +1955,7 @@ fn item_constant<'a, 'tcx>(
})
}
fn item_struct<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
s: &'a clean::Struct,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display {
fmt::from_fn(|w| {
wrap_item(w, |w| {
render_attributes_in_code(w, it, cx);
@ -2056,12 +1979,12 @@ fn item_struct<'a, 'tcx>(
})
}
fn item_fields<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
fields: &'a [clean::Item],
fn item_fields(
cx: &Context<'_>,
it: &clean::Item,
fields: &[clean::Item],
ctor_kind: Option<CtorKind>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
fmt::from_fn(move |w| {
let mut fields = fields
.iter()
@ -2111,12 +2034,12 @@ fn item_fields<'a, 'tcx>(
})
}
fn item_static<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
s: &'a clean::Static,
fn item_static(
cx: &Context<'_>,
it: &clean::Item,
s: &clean::Static,
safety: Option<hir::Safety>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
) -> impl fmt::Display {
fmt::from_fn(move |w| {
wrap_item(w, |w| {
render_attributes_in_code(w, it, cx);
@ -2135,10 +2058,7 @@ fn item_static<'a, 'tcx>(
})
}
fn item_foreign_type<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_foreign_type(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
fmt::from_fn(|w| {
wrap_item(w, |w| {
w.write_str("extern {\n")?;
@ -2155,10 +2075,7 @@ fn item_foreign_type<'a, 'tcx>(
})
}
fn item_keyword<'a, 'tcx>(
cx: &'a Context<'tcx>,
it: &'a clean::Item,
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn item_keyword(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
document(cx, it, None, HeadingOffset::H2)
}
@ -2268,18 +2185,14 @@ pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
s
}
pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display + '_ {
pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display {
fmt::from_fn(move |f| match ty {
ItemType::Module => write!(f, "{}index.html", ensure_trailing_slash(name)),
_ => write!(f, "{ty}.{name}.html"),
})
}
fn bounds<'a, 'tcx>(
bounds: &'a [clean::GenericBound],
trait_alias: bool,
cx: &'a Context<'tcx>,
) -> impl Display + 'a + Captures<'tcx> {
fn bounds(bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> impl Display {
(!bounds.is_empty())
.then_some(fmt::from_fn(move |f| {
let has_lots_of_bounds = bounds.len() > 2;
@ -2329,13 +2242,13 @@ impl Ord for ImplString {
}
}
fn render_implementor<'a, 'tcx>(
cx: &'a Context<'tcx>,
implementor: &'a Impl,
trait_: &'a clean::Item,
implementor_dups: &'a FxHashMap<Symbol, (DefId, bool)>,
aliases: &'a [String],
) -> impl fmt::Display + 'a + Captures<'tcx> {
fn render_implementor(
cx: &Context<'_>,
implementor: &Impl,
trait_: &clean::Item,
implementor_dups: &FxHashMap<Symbol, (DefId, bool)>,
aliases: &[String],
) -> impl fmt::Display {
// If there's already another implementor that has the same abridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let use_absolute = match implementor.inner_impl().for_ {
@ -2364,12 +2277,12 @@ fn render_implementor<'a, 'tcx>(
)
}
fn render_union<'a, 'cx: 'a>(
it: &'a clean::Item,
g: Option<&'a clean::Generics>,
fields: &'a [clean::Item],
cx: &'a Context<'cx>,
) -> impl Display + 'a + Captures<'cx> {
fn render_union(
it: &clean::Item,
g: Option<&clean::Generics>,
fields: &[clean::Item],
cx: &Context<'_>,
) -> impl Display {
fmt::from_fn(move |mut f| {
write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?;
@ -2421,15 +2334,15 @@ fn render_union<'a, 'cx: 'a>(
})
}
fn render_struct<'a, 'tcx>(
it: &'a clean::Item,
g: Option<&'a clean::Generics>,
fn render_struct(
it: &clean::Item,
g: Option<&clean::Generics>,
ty: Option<CtorKind>,
fields: &'a [clean::Item],
tab: &'a str,
fields: &[clean::Item],
tab: &str,
structhead: bool,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
cx: &Context<'_>,
) -> impl fmt::Display {
fmt::from_fn(move |w| {
write!(
w,
@ -2457,15 +2370,15 @@ fn render_struct<'a, 'tcx>(
})
}
fn render_struct_fields<'a, 'tcx>(
g: Option<&'a clean::Generics>,
fn render_struct_fields(
g: Option<&clean::Generics>,
ty: Option<CtorKind>,
fields: &'a [clean::Item],
tab: &'a str,
fields: &[clean::Item],
tab: &str,
structhead: bool,
has_stripped_entries: bool,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
cx: &Context<'_>,
) -> impl fmt::Display {
fmt::from_fn(move |w| {
match ty {
None => {
@ -2581,7 +2494,7 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
}
fn document_non_exhaustive(item: &clean::Item) -> impl Display + '_ {
fn document_non_exhaustive(item: &clean::Item) -> impl Display {
fmt::from_fn(|f| {
if item.is_non_exhaustive() {
write!(

View file

@ -2,7 +2,6 @@ use std::fmt;
use rinja::Template;
use rustc_abi::{Primitive, TagEncoding, Variants};
use rustc_data_structures::captures::Captures;
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::LayoutError;
@ -26,10 +25,7 @@ struct TypeLayoutSize {
size: u64,
}
pub(crate) fn document_type_layout<'a, 'cx: 'a>(
cx: &'a Context<'cx>,
ty_def_id: DefId,
) -> impl fmt::Display + 'a + Captures<'cx> {
pub(crate) fn document_type_layout(cx: &Context<'_>, ty_def_id: DefId) -> impl fmt::Display {
fmt::from_fn(move |f| {
if !cx.shared.show_type_layout {
return Ok(());

View file

@ -333,7 +333,7 @@ pub(crate) fn print_src(
source_context: &SourceContext<'_>,
) {
let mut lines = s.lines().count();
let line_info = if let SourceContext::Embedded(ref info) = source_context {
let line_info = if let SourceContext::Embedded(info) = source_context {
highlight::LineInfo::new_scraped(lines as u32, info.offset as u32)
} else {
highlight::LineInfo::new(lines as u32)

View file

@ -147,7 +147,7 @@ pub fn main() {
#[cfg(target_os = "macos")]
{
extern "C" {
unsafe extern "C" {
fn _rjem_je_zone_register();
}

View file

@ -58,7 +58,7 @@ fn filter_assoc_items_by_name_and_namespace(
assoc_items_of: DefId,
ident: Ident,
ns: Namespace,
) -> impl Iterator<Item = &ty::AssocItem> + '_ {
) -> impl Iterator<Item = &ty::AssocItem> {
tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| {
item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
})

View file

@ -190,6 +190,9 @@ pub struct Config {
/// The cargo executable.
pub cargo_path: Option<PathBuf>,
/// Rustc executable used to compile run-make recipes.
pub stage0_rustc_path: Option<PathBuf>,
/// The rustdoc executable.
pub rustdoc_path: Option<PathBuf>,

View file

@ -54,6 +54,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
.reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
.reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
.optopt("", "cargo-path", "path to cargo to use for compiling", "PATH")
.optopt(
"",
"stage0-rustc-path",
"path to rustc to use for compiling run-make recipes",
"PATH",
)
.optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
.optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH")
.reqopt("", "python", "path to python to use for doc tests", "PATH")
@ -320,6 +326,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
rustc_path: opt_path(matches, "rustc-path"),
cargo_path: matches.opt_str("cargo-path").map(PathBuf::from),
stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(PathBuf::from),
rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from),
python: matches.opt_str("python").unwrap(),

View file

@ -173,7 +173,8 @@ impl TestCx<'_> {
fn run_rmake_v2_test(&self) {
// For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe
// (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust
// library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`.
// library and is available under
// `build/$HOST/stage0-bootstrap-tools/$TARGET/release/librun_make_support.rlib`.
//
// 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support`
// library.
@ -224,25 +225,21 @@ impl TestCx<'_> {
//
// ```
// build/<target_triple>/
// ├── stageN-tools-bin/
// │ └── librun_make_support.rlib // <- support rlib itself
// ├── stageN-tools/
// │ ├── release/deps/ // <- deps of deps
// │ └── <host_triple>/release/deps/ // <- deps
// ├── stage0-bootstrap-tools/
// │ ├── <host_triple>/release/librun_make_support.rlib // <- support rlib itself
// │ ├── <host_triple>/release/deps/ // <- deps
// │ └── release/deps/ // <- deps of deps
// ```
//
// FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the
// support lib and its deps are organized, can't we copy them to the tools-bin dir as
// well?), but this seems to work for now.
// support lib and its deps are organized), but this seems to work for now.
let stage_number = self.config.stage;
let tools_bin = host_build_root.join("stage0-bootstrap-tools");
let support_host_path = tools_bin.join(&self.config.host).join("release");
let support_lib_path = support_host_path.join("librun_make_support.rlib");
let stage_tools_bin = host_build_root.join(format!("stage{stage_number}-tools-bin"));
let support_lib_path = stage_tools_bin.join("librun_make_support.rlib");
let stage_tools = host_build_root.join(format!("stage{stage_number}-tools"));
let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps");
let support_lib_deps_deps = stage_tools.join("release").join("deps");
let support_lib_deps = support_host_path.join("deps");
let support_lib_deps_deps = tools_bin.join("release").join("deps");
// To compile the recipe with rustc, we need to provide suitable dynamic library search
// paths to rustc. This includes both:
@ -253,12 +250,6 @@ impl TestCx<'_> {
let base_dylib_search_paths =
Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap()));
let host_dylib_search_paths = {
let mut paths = vec![self.config.compile_lib_path.clone()];
paths.extend(base_dylib_search_paths.iter().cloned());
paths
};
// Calculate the paths of the recipe binary. As previously discussed, this is placed at
// `<base_dir>/<bin_name>` with `bin_name` being `rmake` or `rmake.exe` depending on
// platform.
@ -268,7 +259,15 @@ impl TestCx<'_> {
p
};
let mut rustc = Command::new(&self.config.rustc_path);
// run-make-support and run-make tests are compiled using the stage0 compiler
// If the stage is 0, then the compiler that we test (either bootstrap or an explicitly
// set compiler) is the one that actually compiled run-make-support.
let stage0_rustc = self
.config
.stage0_rustc_path
.as_ref()
.expect("stage0 rustc is required to run run-make tests");
let mut rustc = Command::new(&stage0_rustc);
rustc
.arg("-o")
.arg(&recipe_bin)
@ -282,35 +281,12 @@ impl TestCx<'_> {
.arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
.arg("--edition=2021")
.arg(&self.testpaths.file.join("rmake.rs"))
.arg("-Cprefer-dynamic")
// Provide necessary library search paths for rustc.
.env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap());
.arg("-Cprefer-dynamic");
// In test code we want to be very pedantic about values being silently discarded that are
// annotated with `#[must_use]`.
rustc.arg("-Dunused_must_use");
// > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc
// > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is
// > compiled using the bootstrap rustc wrapper which sets `--sysroot
// > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile
// > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the
// > `libstd.rlib` against which `librun_make_support.rlib` is compiled.
//
// The gist here is that we have to pass the proper stage0 sysroot if we want
//
// ```
// $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0
// ```
//
// to work correctly.
//
// See <https://github.com/rust-lang/rust/pull/122248> for more background.
let stage0_sysroot = host_build_root.join("stage0-sysroot");
if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() {
rustc.arg("--sysroot").arg(&stage0_sysroot);
}
// Now run rustc to build the recipe.
let res = self.run_command_to_procres(&mut rustc);
if !res.status.success() {
@ -320,35 +296,24 @@ impl TestCx<'_> {
// To actually run the recipe, we have to provide the recipe with a bunch of information
// provided through env vars.
// Compute stage-specific standard library paths.
let stage_std_path = host_build_root.join(format!("stage{stage_number}")).join("lib");
// Compute dynamic library search paths for recipes.
// These dylib directories are needed to **execute the recipe**.
let recipe_dylib_search_paths = {
let mut paths = base_dylib_search_paths.clone();
// For stage 0, we need to explicitly include the stage0-sysroot libstd dylib.
// See <https://github.com/rust-lang/rust/issues/135373>.
if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() {
paths.push(
stage0_sysroot.join("lib").join("rustlib").join(&self.config.host).join("lib"),
);
}
paths.push(support_lib_path.parent().unwrap().to_path_buf());
paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib"));
paths.push(
stage0_rustc
.parent()
.unwrap()
.parent()
.unwrap()
.join("lib")
.join("rustlib")
.join(&self.config.host)
.join("lib"),
);
paths
};
// Compute runtime library search paths for recipes. This is target-specific.
let target_runtime_dylib_search_paths = {
let mut paths = vec![rmake_out_dir.clone()];
paths.extend(base_dylib_search_paths.iter().cloned());
paths
};
// FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and
// `TARGET_RPATH_DIR`, it is **extremely** confusing!
let mut cmd = Command::new(&recipe_bin);
cmd.current_dir(&rmake_out_dir)
.stdout(Stdio::piped())
@ -357,9 +322,14 @@ impl TestCx<'_> {
// example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows.
.env("LD_LIB_PATH_ENVVAR", dylib_env_var())
// Provide the dylib search paths.
// This is required to run the **recipe** itself.
.env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap())
// Provide runtime dylib search paths.
.env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap())
// Provide the directory to libraries that are needed to run the *compiler* invoked
// by the recipe.
.env("HOST_RUSTC_DYLIB_PATH", &self.config.compile_lib_path)
// Provide the directory to libraries that might be needed to run binaries created
// by a compiler invoked by the recipe.
.env("TARGET_EXE_DYLIB_PATH", &self.config.run_lib_path)
// Provide the target.
.env("TARGET", &self.config.target)
// Some tests unfortunately still need Python, so provide path to a Python interpreter.
@ -370,13 +340,6 @@ impl TestCx<'_> {
.env("BUILD_ROOT", &host_build_root)
// Provide path to stage-corresponding rustc.
.env("RUSTC", &self.config.rustc_path)
// Provide the directory to libraries that are needed to run the *compiler*. This is not
// to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the
// recipe wants to invoke rustc.
.env("HOST_RPATH_DIR", &self.config.compile_lib_path)
// Provide the directory to libraries that might be needed to run compiled binaries
// (further compiled by the recipe!).
.env("TARGET_RPATH_DIR", &self.config.run_lib_path)
// Provide which LLVM components are available (e.g. which LLVM components are provided
// through a specific CI runner).
.env("LLVM_COMPONENTS", &self.config.llvm_components);

View file

@ -389,6 +389,7 @@ fn main() -> anyhow::Result<()> {
"clippy",
"miri",
"rustfmt",
"gcc",
] {
build_args.extend(["--skip".to_string(), target.to_string()]);
}

View file

@ -1,33 +1,10 @@
use std::time::Duration;
use build_helper::metrics::{JsonNode, JsonRoot};
use build_helper::metrics::{BuildStep, JsonRoot, format_build_steps};
use camino::Utf8Path;
use crate::timer::TimerSection;
#[derive(Clone, Debug)]
pub struct BuildStep {
r#type: String,
children: Vec<BuildStep>,
duration: Duration,
}
impl BuildStep {
pub fn find_all_by_type(&self, r#type: &str) -> Vec<&BuildStep> {
let mut result = Vec::new();
self.find_by_type(r#type, &mut result);
result
}
fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a BuildStep>) {
if self.r#type == r#type {
result.push(self);
}
for child in &self.children {
child.find_by_type(r#type, result);
}
}
}
/// Loads the metrics of the most recent bootstrap execution from a metrics.json file.
pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> {
let content = std::fs::read(path.as_std_path())?;
@ -37,30 +14,7 @@ pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> {
.pop()
.ok_or_else(|| anyhow::anyhow!("No bootstrap invocation found in metrics file"))?;
fn parse(node: JsonNode) -> Option<BuildStep> {
match node {
JsonNode::RustbuildStep {
type_: kind,
children,
duration_excluding_children_sec,
..
} => {
let children: Vec<_> = children.into_iter().filter_map(parse).collect();
let children_duration = children.iter().map(|c| c.duration).sum::<Duration>();
Some(BuildStep {
r#type: kind.to_string(),
children,
duration: children_duration
+ Duration::from_secs_f64(duration_excluding_children_sec),
})
}
JsonNode::TestSuite(_) => None,
}
}
let duration = Duration::from_secs_f64(invocation.duration_including_children_sec);
let children: Vec<_> = invocation.children.into_iter().filter_map(parse).collect();
Ok(BuildStep { r#type: "root".to_string(), children, duration })
Ok(BuildStep::from_invocation(&invocation))
}
/// Logs the individual metrics in a table and add Rustc and LLVM durations to the passed
@ -82,27 +36,6 @@ pub fn record_metrics(metrics: &BuildStep, timer: &mut TimerSection) {
timer.add_duration("Rustc", rustc_duration);
}
log_metrics(metrics);
}
fn log_metrics(metrics: &BuildStep) {
use std::fmt::Write;
let mut substeps: Vec<(u32, &BuildStep)> = Vec::new();
fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) {
substeps.push((level, step));
for child in &step.children {
visit(child, level + 1, substeps);
}
}
visit(metrics, 0, &mut substeps);
let mut output = String::new();
for (level, step) in substeps {
let label = format!("{}{}", ".".repeat(level as usize), step.r#type);
writeln!(output, "{label:<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap();
}
let output = format_build_steps(metrics);
log::info!("Build step durations\n{output}");
}

View file

@ -5,7 +5,7 @@ use std::str::FromStr as _;
use crate::command::Command;
use crate::env::env_var;
use crate::path_helpers::cwd;
use crate::util::set_host_rpath;
use crate::util::set_host_compiler_dylib_path;
use crate::{is_aix, is_darwin, is_msvc, is_windows, uname};
/// Construct a new `rustc` invocation. This will automatically set the library
@ -15,8 +15,8 @@ pub fn rustc() -> Rustc {
Rustc::new()
}
/// Construct a plain `rustc` invocation with no flags set. Note that [`set_host_rpath`]
/// still presets the environment variable `HOST_RPATH_DIR` by default.
/// Construct a plain `rustc` invocation with no flags set. Note that [`set_host_compiler_dylib_path`]
/// still presets the environment variable `HOST_RUSTC_DYLIB_PATH` by default.
#[track_caller]
pub fn bare_rustc() -> Rustc {
Rustc::bare()
@ -44,7 +44,7 @@ pub fn rustc_path() -> String {
#[track_caller]
fn setup_common() -> Command {
let mut cmd = Command::new(rustc_path());
set_host_rpath(&mut cmd);
set_host_compiler_dylib_path(&mut cmd);
cmd
}

View file

@ -2,16 +2,10 @@ use std::ffi::OsStr;
use std::path::Path;
use crate::command::Command;
use crate::env::{env_var, env_var_os};
use crate::util::set_host_rpath;
use crate::env::env_var;
use crate::util::set_host_compiler_dylib_path;
/// Construct a plain `rustdoc` invocation with no flags set.
#[track_caller]
pub fn bare_rustdoc() -> Rustdoc {
Rustdoc::bare()
}
/// Construct a new `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
/// Construct a new `rustdoc` invocation.
#[track_caller]
pub fn rustdoc() -> Rustdoc {
Rustdoc::new()
@ -29,23 +23,15 @@ crate::macros::impl_common_helpers!(Rustdoc);
fn setup_common() -> Command {
let rustdoc = env_var("RUSTDOC");
let mut cmd = Command::new(rustdoc);
set_host_rpath(&mut cmd);
set_host_compiler_dylib_path(&mut cmd);
cmd
}
impl Rustdoc {
/// Construct a bare `rustdoc` invocation.
#[track_caller]
pub fn bare() -> Self {
let cmd = setup_common();
Self { cmd }
}
/// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
#[track_caller]
pub fn new() -> Self {
let mut cmd = setup_common();
cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR"));
let cmd = setup_common();
Self { cmd }
}

View file

@ -67,7 +67,7 @@ pub use llvm::{
};
pub use python::python_command;
pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc};
pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
pub use rustdoc::{rustdoc, Rustdoc};
/// [`diff`][mod@diff] is implemented in terms of the [similar] library.
///

View file

@ -1,10 +1,10 @@
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::{env, panic};
use crate::command::{Command, CompletedProcess};
use crate::util::{handle_failed_output, set_host_rpath};
use crate::{cwd, env_var, is_windows};
use crate::util::handle_failed_output;
use crate::{cwd, env_var};
#[track_caller]
fn run_common(name: &str, args: Option<&[&str]>) -> Command {
@ -18,10 +18,11 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command {
cmd.arg(arg);
}
}
cmd.env(&ld_lib_path_envvar, {
let mut paths = vec![];
paths.push(cwd());
for p in env::split_paths(&env_var("TARGET_RPATH_ENV")) {
for p in env::split_paths(&env_var("TARGET_EXE_DYLIB_PATH")) {
paths.push(p.to_path_buf());
}
for p in env::split_paths(&env_var(&ld_lib_path_envvar)) {
@ -31,15 +32,6 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command {
});
cmd.env("LC_ALL", "C"); // force english locale
if is_windows() {
let mut paths = vec![];
for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) {
paths.push(p.to_path_buf());
}
paths.push(Path::new(&env_var("TARGET_RPATH_DIR")).to_path_buf());
cmd.env("PATH", env::join_paths(paths.iter()).unwrap());
}
cmd
}
@ -84,7 +76,6 @@ pub fn run_fail(name: &str) -> CompletedProcess {
#[track_caller]
pub fn cmd<S: AsRef<OsStr>>(program: S) -> Command {
let mut command = Command::new(program);
set_host_rpath(&mut command);
command.env("LC_ALL", "C"); // force english locale
command
}

View file

@ -24,13 +24,13 @@ pub(crate) fn handle_failed_output(
std::process::exit(1)
}
/// Set the runtime library path as needed for running the host rustc/rustdoc/etc.
pub(crate) fn set_host_rpath(cmd: &mut Command) {
/// Set the runtime library paths as needed for running the host compilers (rustc/rustdoc/etc).
pub(crate) fn set_host_compiler_dylib_path(cmd: &mut Command) {
let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR");
cmd.env(&ld_lib_path_envvar, {
let mut paths = vec![];
paths.push(cwd());
paths.push(PathBuf::from(env_var("HOST_RPATH_DIR")));
paths.push(PathBuf::from(env_var("HOST_RUSTC_DYLIB_PATH")));
for p in std::env::split_paths(&env_var(&ld_lib_path_envvar)) {
paths.push(p.to_path_buf());
}

View file

@ -1,7 +1,7 @@
[package]
name = "rustdoc-tool"
version = "0.0.0"
edition = "2021"
edition = "2024"
# Cargo adds a number of paths to the dylib search path on windows, which results in
# the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"

View file

@ -1,7 +1,8 @@
// ignore-tidy-linelength
// Test that if we build `b` against a version of `a` that has
// one set of types, it will not run with a dylib that has a different set of types.
// Test that if we build `b` against a version of `a` that has one set of types, it will not run
// with a dylib that has a different set of types.
//@ ignore-cross-compile
// Reason: the compiled binary is executed
use run_make_support::{run, run_fail, rustc};

View file

@ -3,10 +3,10 @@
// ensures the output of rustdoc's help menu is as expected.
// See https://github.com/rust-lang/rust/issues/88756
use run_make_support::{bare_rustdoc, diff};
use run_make_support::{diff, rustdoc};
fn main() {
let out = bare_rustdoc().run().stdout_utf8();
let out = rustdoc().run().stdout_utf8();
diff()
.expected_file("output-default.stdout")
.actual_text("actual", out)

View file

@ -5,13 +5,13 @@
//@ needs-git-hash
use run_make_support::{bare_rustc, bare_rustdoc, regex};
use run_make_support::{bare_rustc, regex, rustdoc};
fn main() {
let out_rustc =
bare_rustc().arg("--version").arg("--verbose").run().stdout_utf8().to_lowercase();
let out_rustdoc =
bare_rustdoc().arg("--version").arg("--verbose").run().stdout_utf8().to_lowercase();
rustdoc().arg("--version").arg("--verbose").run().stdout_utf8().to_lowercase();
let re =
regex::Regex::new(r#"commit-hash: [0-9a-f]{40}\ncommit-date: [0-9]{4}-[0-9]{2}-[0-9]{2}"#)
.unwrap();