> FromIterator for PathBuf {
+ /// Creates a new `PathBuf` from the [`Path`] elements of an iterator.
+ ///
+ /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path
+ /// [components](Components).
+ ///
+ /// # Examples
+ /// ```
+ /// # use std::path::PathBuf;
+ /// let path = PathBuf::from_iter(["/tmp", "foo", "bar"]);
+ /// assert_eq!(path, PathBuf::from("/tmp/foo/bar"));
+ /// ```
+ ///
+ /// See documentation for [`push`](Self::push) for more details on how the path is constructed.
fn from_iter>(iter: I) -> PathBuf {
let mut buf = PathBuf::new();
buf.extend(iter);
@@ -1891,6 +1904,20 @@ fn from_iter>(iter: I) -> PathBuf {
#[stable(feature = "rust1", since = "1.0.0")]
impl> Extend for PathBuf {
+ /// Extends `self` with [`Path`] elements from `iter`.
+ ///
+ /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path
+ /// [components](Components).
+ ///
+ /// # Examples
+ /// ```
+ /// # use std::path::PathBuf;
+ /// let mut path = PathBuf::from("/tmp");
+ /// path.extend(["foo", "bar", "file.txt"]);
+ /// assert_eq!(path, PathBuf::from("/tmp/foo/bar/file.txt"));
+ /// ```
+ ///
+ /// See documentation for [`push`](Self::push) for more details on how the path is constructed.
fn extend>(&mut self, iter: I) {
iter.into_iter().for_each(move |p| self.push(p.as_ref()));
}
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 0c8e66335609..a6ca699e2824 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -44,6 +44,7 @@ dependencies = [
"fd-lock",
"home",
"ignore",
+ "insta",
"junction",
"libc",
"object",
@@ -158,6 +159,18 @@ dependencies = [
"cc",
]
+[[package]]
+name = "console"
+version = "0.15.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
+dependencies = [
+ "encode_unicode",
+ "libc",
+ "once_cell",
+ "windows-sys 0.59.0",
+]
+
[[package]]
name = "cpufeatures"
version = "0.2.15"
@@ -218,6 +231,12 @@ dependencies = [
"crypto-common",
]
+[[package]]
+name = "encode_unicode"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
[[package]]
name = "errno"
version = "0.3.11"
@@ -323,6 +342,17 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "insta"
+version = "1.43.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371"
+dependencies = [
+ "console",
+ "once_cell",
+ "similar",
+]
+
[[package]]
name = "itoa"
version = "1.0.11"
@@ -675,6 +705,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+[[package]]
+name = "similar"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
+
[[package]]
name = "smallvec"
version = "1.13.2"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index b12b3dfc7b2a..9785a306c9b1 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -84,6 +84,7 @@ features = [
[dev-dependencies]
pretty_assertions = "1.4"
tempfile = "3.15.0"
+insta = "1.43"
# We care a lot about bootstrap's compile times, so don't include debuginfo for
# dependencies, only bootstrap itself.
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index f9d7c811f600..5ff999f01a95 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -200,6 +200,10 @@ please file issues on the [Rust issue tracker][rust-issue-tracker].
[rust-bootstrap-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/t-infra.2Fbootstrap
[rust-issue-tracker]: https://github.com/rust-lang/rust/issues
+## Testing
+
+To run bootstrap tests, execute `x test bootstrap`. If you want to bless snapshot tests, then install `cargo-insta` (`cargo install cargo-insta`) and then run `cargo insta review --manifest-path src/bootstrap/Cargo.toml`.
+
## Changelog
Because we do not release bootstrap with versions, we also do not maintain CHANGELOG files. To
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index ebb926d81cef..f9f82b800419 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2009,7 +2009,7 @@ fn run(self, builder: &Builder<'_>) {
// Note that if we encounter `PATH` we make sure to append to our own `PATH`
// rather than stomp over it.
if !builder.config.dry_run() && target.is_msvc() {
- for (k, v) in builder.cc.borrow()[&target].env() {
+ for (k, v) in builder.cc[&target].env() {
if k != "PATH" {
cmd.env(k, v);
}
@@ -2026,8 +2026,7 @@ fn run(self, builder: &Builder<'_>) {
// address sanitizer enabled (e.g., ntdll.dll).
cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1");
// Add the address sanitizer runtime to the PATH - it is located next to cl.exe.
- let asan_runtime_path =
- builder.cc.borrow()[&target].path().parent().unwrap().to_path_buf();
+ let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf();
let old_path = cmd
.get_envs()
.find_map(|(k, v)| (k == "PATH").then_some(v))
@@ -3059,6 +3058,8 @@ fn run(self, builder: &Builder<'_>) {
cargo
.rustflag("-Cdebuginfo=2")
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
+ // Needed for insta to correctly write pending snapshots to the right directories.
+ .env("INSTA_WORKSPACE_ROOT", &builder.src)
.env("RUSTC_BOOTSTRAP", "1");
// bootstrap tests are racy on directory creation so just run them one at a time.
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index f64d67341cfe..237efaefada3 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1334,7 +1334,7 @@ pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand {
if compiler.host.is_msvc() {
let curpaths = env::var_os("PATH").unwrap_or_default();
let curpaths = env::split_paths(&curpaths).collect::>();
- for (k, v) in self.cc.borrow()[&compiler.host].env() {
+ for (k, v) in self.cc[&compiler.host].env() {
if k != "PATH" {
continue;
}
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index c6cfdb69356c..0e3c3aaee0ff 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -278,9 +278,7 @@ fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
self.rustdocflags.arg(&arg);
}
- if !builder.config.dry_run()
- && builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
- {
+ if !builder.config.dry_run() && builder.cc[&target].args().iter().any(|arg| arg == "-gz") {
self.rustflags.arg("-Clink-arg=-gz");
}
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 887db683f789..7433f0b0f3b4 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -5,7 +5,7 @@
use std::hash::Hash;
use std::ops::Deref;
use std::path::{Path, PathBuf};
-use std::sync::LazyLock;
+use std::sync::{LazyLock, OnceLock};
use std::time::{Duration, Instant};
use std::{env, fs};
@@ -60,6 +60,9 @@ pub struct Builder<'a> {
/// to do. For example: with `./x check foo bar` we get `paths=["foo",
/// "bar"]`.
pub paths: Vec,
+
+ /// Cached list of submodules from self.build.src.
+ submodule_paths_cache: OnceLock>,
}
impl Deref for Builder<'_> {
@@ -687,7 +690,7 @@ pub fn path(self, path: &str) -> Self {
///
/// [`path`]: ShouldRun::path
pub fn paths(mut self, paths: &[&str]) -> Self {
- let submodules_paths = build_helper::util::parse_gitmodules(&self.builder.src);
+ let submodules_paths = self.builder.submodule_paths();
self.paths.insert(PathSet::Set(
paths
@@ -1180,6 +1183,7 @@ fn new_internal(build: &Build, kind: Kind, paths: Vec) -> Builder<'_> {
stack: RefCell::new(Vec::new()),
time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
paths,
+ submodule_paths_cache: Default::default(),
}
}
@@ -1510,6 +1514,19 @@ pub fn llvm_config(&self, target: TargetSelection) -> Option {
None
}
+ /// Updates all submodules, and exits with an error if submodule
+ /// management is disabled and the submodule does not exist.
+ pub fn require_and_update_all_submodules(&self) {
+ for submodule in self.submodule_paths() {
+ self.require_submodule(submodule, None);
+ }
+ }
+
+ /// Get all submodules from the src directory.
+ pub fn submodule_paths(&self) -> &[String] {
+ self.submodule_paths_cache.get_or_init(|| build_helper::util::parse_gitmodules(&self.src))
+ }
+
/// Ensure that a given step is built, returning its output. This will
/// cache the step, so it is safe (and good!) to call this as often as
/// needed to ensure that all dependencies are built.
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index a26a96f2815e..d07df7f4a841 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -15,11 +15,12 @@
static TEST_TRIPLE_3: &str = "i686-unknown-netbsd";
fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
- configure_with_args(&[cmd.to_owned()], host, target)
+ configure_with_args(&[cmd], host, target)
}
-fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config {
- let mut config = Config::parse(Flags::parse(cmd));
+fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config {
+ let cmd = cmd.iter().copied().map(String::from).collect::>();
+ let mut config = Config::parse(Flags::parse(&cmd));
// don't save toolstates
config.save_toolstates = None;
config.set_dry_run(DryRun::SelfCheck);
@@ -67,7 +68,7 @@ fn run_build(paths: &[PathBuf], config: Config) -> Cache {
fn check_cli(paths: [&str; N]) {
run_build(
&paths.map(PathBuf::from),
- configure_with_args(&paths.map(String::from), &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
+ configure_with_args(&paths, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
);
}
@@ -1000,8 +1001,7 @@ fn test_sysroot_target_bindir() {
/// cg_gcc tests instead.
#[test]
fn test_test_compiler() {
- let cmd = &["test", "compiler"].map(str::to_owned);
- let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+ let config = configure_with_args(&["test", "compiler"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
let cache = run_build(&config.paths.clone(), config);
let compiler = cache.contains::();
@@ -1034,8 +1034,7 @@ struct Case {
// Print each test case so that if one fails, the most recently printed
// case is the one that failed.
println!("Testing case: {cmd:?}");
- let cmd = cmd.iter().copied().map(str::to_owned).collect::>();
- let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+ let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
let mut cache = run_build(&config.paths.clone(), config);
let modes =
@@ -1207,8 +1206,7 @@ fn test_get_tool_rustc_compiler() {
/// of `Any { .. }`.
#[test]
fn step_cycle_debug() {
- let cmd = ["run", "cyclic-step"].map(str::to_owned);
- let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+ let config = configure_with_args(&["run", "cyclic-step"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
let err = panic::catch_unwind(|| run_build(&config.paths.clone(), config)).unwrap_err();
let err = err.downcast_ref::().unwrap().as_str();
@@ -1233,3 +1231,81 @@ struct MyStruct {
// Downcasting to the underlying type should succeed.
assert_eq!(x.downcast_ref::(), Some(&MyStruct { x: 7 }));
}
+
+/// The staging tests use insta for snapshot testing.
+/// See bootstrap's README on how to bless the snapshots.
+mod staging {
+ use crate::core::builder::tests::{
+ TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build,
+ };
+
+ #[test]
+ fn build_compiler_stage_1() {
+ let mut cache = run_build(
+ &["compiler".into()],
+ configure_with_args(&["build", "--stage", "1"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
+ );
+ let steps = cache.into_executed_steps();
+ insta::assert_snapshot!(render_steps(&steps), @r"
+ [build] rustc 0 -> std 0
+ [build] llvm
+ [build] rustc 0 -> rustc 1
+ [build] rustc 0 -> rustc 1
+ ");
+ }
+}
+
+/// Renders the executed bootstrap steps for usage in snapshot tests with insta.
+/// Only renders certain important steps.
+/// Each value in `steps` should be a tuple of (Step, step output).
+fn render_steps(steps: &[(Box, Box)]) -> String {
+ steps
+ .iter()
+ .filter_map(|(step, output)| {
+ // FIXME: implement an optional method on Step to produce metadata for test, instead
+ // of this downcasting
+ if let Some((rustc, output)) = downcast_step::(step, output) {
+ Some(format!(
+ "[build] {} -> {}",
+ render_compiler(rustc.build_compiler),
+ // FIXME: return the correct stage from the `Rustc` step, now it behaves weirdly
+ render_compiler(Compiler::new(rustc.build_compiler.stage + 1, rustc.target)),
+ ))
+ } else if let Some((std, output)) = downcast_step::(step, output) {
+ Some(format!(
+ "[build] {} -> std {} <{}>",
+ render_compiler(std.compiler),
+ std.compiler.stage,
+ std.target
+ ))
+ } else if let Some((llvm, output)) = downcast_step::(step, output) {
+ Some(format!("[build] llvm <{}>", llvm.target))
+ } else {
+ None
+ }
+ })
+ .map(|line| {
+ line.replace(TEST_TRIPLE_1, "target1")
+ .replace(TEST_TRIPLE_2, "target2")
+ .replace(TEST_TRIPLE_3, "target3")
+ })
+ .collect::>()
+ .join("\n")
+}
+
+fn downcast_step<'a, S: Step>(
+ step: &'a Box,
+ output: &'a Box,
+) -> Option<(&'a S, &'a S::Output)> {
+ let Some(step) = step.downcast_ref::() else {
+ return None;
+ };
+ let Some(output) = output.downcast_ref::() else {
+ return None;
+ };
+ Some((step, output))
+}
+
+fn render_compiler(compiler: Compiler) -> String {
+ format!("rustc {} <{}>", compiler.stage, compiler.host)
+}
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 7254c653a2db..f1628f34ddab 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -17,7 +17,7 @@
//! also check out the `src/bootstrap/README.md` file for more information.
#![cfg_attr(test, allow(unused))]
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
use std::collections::{BTreeSet, HashMap, HashSet};
use std::fmt::Display;
use std::path::{Path, PathBuf};
@@ -189,10 +189,12 @@ pub struct Build {
// Runtime state filled in later on
// C/C++ compilers and archiver for all targets
- cc: RefCell>,
- cxx: RefCell>,
- ar: RefCell>,
- ranlib: RefCell>,
+ cc: HashMap,
+ cxx: HashMap,
+ ar: HashMap,
+ ranlib: HashMap,
+ wasi_sdk_path: Option,
+
// Miscellaneous
// allow bidirectional lookups: both name -> path and path -> name
crates: HashMap,
@@ -466,10 +468,11 @@ pub fn new(mut config: Config) -> Build {
enzyme_info,
in_tree_llvm_info,
in_tree_gcc_info,
- cc: RefCell::new(HashMap::new()),
- cxx: RefCell::new(HashMap::new()),
- ar: RefCell::new(HashMap::new()),
- ranlib: RefCell::new(HashMap::new()),
+ cc: HashMap::new(),
+ cxx: HashMap::new(),
+ ar: HashMap::new(),
+ ranlib: HashMap::new(),
+ wasi_sdk_path: env::var_os("WASI_SDK_PATH").map(PathBuf::from),
crates: HashMap::new(),
crate_paths: HashMap::new(),
is_sudo,
@@ -498,7 +501,7 @@ pub fn new(mut config: Config) -> Build {
}
build.verbose(|| println!("finding compilers"));
- utils::cc_detect::find(&build);
+ utils::cc_detect::fill_compilers(&mut build);
// When running `setup`, the profile is about to change, so any requirements we have now may
// be different on the next invocation. Don't check for them until the next time x.py is
// run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
@@ -593,14 +596,6 @@ pub fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) {
}
}
- /// Updates all submodules, and exits with an error if submodule
- /// management is disabled and the submodule does not exist.
- pub fn require_and_update_all_submodules(&self) {
- for submodule in build_helper::util::parse_gitmodules(&self.src) {
- self.require_submodule(submodule, None);
- }
- }
-
/// If any submodule has been initialized already, sync it unconditionally.
/// This avoids contributors checking in a submodule change by accident.
fn update_existing_submodules(&self) {
@@ -1143,17 +1138,17 @@ fn cc(&self, target: TargetSelection) -> PathBuf {
if self.config.dry_run() {
return PathBuf::new();
}
- self.cc.borrow()[&target].path().into()
+ self.cc[&target].path().into()
}
/// Returns the internal `cc::Tool` for the C compiler.
fn cc_tool(&self, target: TargetSelection) -> Tool {
- self.cc.borrow()[&target].clone()
+ self.cc[&target].clone()
}
/// Returns the internal `cc::Tool` for the C++ compiler.
fn cxx_tool(&self, target: TargetSelection) -> Tool {
- self.cxx.borrow()[&target].clone()
+ self.cxx[&target].clone()
}
/// Returns C flags that `cc-rs` thinks should be enabled for the
@@ -1163,8 +1158,8 @@ fn cc_handled_clags(&self, target: TargetSelection, c: CLang) -> Vec {
return Vec::new();
}
let base = match c {
- CLang::C => self.cc.borrow()[&target].clone(),
- CLang::Cxx => self.cxx.borrow()[&target].clone(),
+ CLang::C => self.cc[&target].clone(),
+ CLang::Cxx => self.cxx[&target].clone(),
};
// Filter out -O and /O (the optimization flags) that we picked up
@@ -1217,7 +1212,7 @@ fn ar(&self, target: TargetSelection) -> Option {
if self.config.dry_run() {
return None;
}
- self.ar.borrow().get(&target).cloned()
+ self.ar.get(&target).cloned()
}
/// Returns the path to the `ranlib` utility for the target specified.
@@ -1225,7 +1220,7 @@ fn ranlib(&self, target: TargetSelection) -> Option {
if self.config.dry_run() {
return None;
}
- self.ranlib.borrow().get(&target).cloned()
+ self.ranlib.get(&target).cloned()
}
/// Returns the path to the C++ compiler for the target specified.
@@ -1233,7 +1228,7 @@ fn cxx(&self, target: TargetSelection) -> Result {
if self.config.dry_run() {
return Ok(PathBuf::new());
}
- match self.cxx.borrow().get(&target) {
+ match self.cxx.get(&target) {
Some(p) => Ok(p.path().into()),
None => Err(format!("target `{target}` is not configured as a host, only as a target")),
}
@@ -1250,7 +1245,7 @@ fn linker(&self, target: TargetSelection) -> Option {
} else if target.contains("vxworks") {
// need to use CXX compiler as linker to resolve the exception functions
// that are only existed in CXX libraries
- Some(self.cxx.borrow()[&target].path().into())
+ Some(self.cxx[&target].path().into())
} else if !self.config.is_host_target(target)
&& helpers::use_host_linker(target)
&& !target.is_msvc()
diff --git a/src/bootstrap/src/utils/build_stamp/tests.rs b/src/bootstrap/src/utils/build_stamp/tests.rs
index 2d7d1f712465..f150266159a2 100644
--- a/src/bootstrap/src/utils/build_stamp/tests.rs
+++ b/src/bootstrap/src/utils/build_stamp/tests.rs
@@ -1,32 +1,28 @@
use std::path::PathBuf;
-use crate::{BuildStamp, Config, Flags};
+use tempfile::TempDir;
-fn temp_dir() -> PathBuf {
- let config =
- Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
- config.tempdir()
-}
+use crate::{BuildStamp, Config, Flags};
#[test]
#[should_panic(expected = "prefix can not start or end with '.'")]
fn test_with_invalid_prefix() {
- let dir = temp_dir();
- BuildStamp::new(&dir).with_prefix(".invalid");
+ let dir = TempDir::new().unwrap();
+ BuildStamp::new(dir.path()).with_prefix(".invalid");
}
#[test]
#[should_panic(expected = "prefix can not start or end with '.'")]
fn test_with_invalid_prefix2() {
- let dir = temp_dir();
- BuildStamp::new(&dir).with_prefix("invalid.");
+ let dir = TempDir::new().unwrap();
+ BuildStamp::new(dir.path()).with_prefix("invalid.");
}
#[test]
fn test_is_up_to_date() {
- let dir = temp_dir();
+ let dir = TempDir::new().unwrap();
- let mut build_stamp = BuildStamp::new(&dir).add_stamp("v1.0.0");
+ let mut build_stamp = BuildStamp::new(dir.path()).add_stamp("v1.0.0");
build_stamp.write().unwrap();
assert!(
@@ -45,9 +41,9 @@ fn test_is_up_to_date() {
#[test]
fn test_with_prefix() {
- let dir = temp_dir();
+ let dir = TempDir::new().unwrap();
- let stamp = BuildStamp::new(&dir).add_stamp("v1.0.0");
+ let stamp = BuildStamp::new(dir.path()).add_stamp("v1.0.0");
assert_eq!(stamp.path.file_name().unwrap(), ".stamp");
let stamp = stamp.with_prefix("test");
diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs
index 46eeffad88c3..0c7374709584 100644
--- a/src/bootstrap/src/utils/cache.rs
+++ b/src/bootstrap/src/utils/cache.rs
@@ -17,6 +17,7 @@
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::HashMap;
+use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::Deref;
@@ -208,25 +209,30 @@ pub fn intern_str(&self, s: &str) -> Interned {
/// any type in its output. It is a write-once cache; values are never evicted,
/// which means that references to the value can safely be returned from the
/// `get()` method.
-#[derive(Debug)]
-pub struct Cache(
- RefCell<
+#[derive(Debug, Default)]
+pub struct Cache {
+ cache: RefCell<
HashMap<
TypeId,
Box, // actually a HashMap>
>,
>,
-);
+ #[cfg(test)]
+ /// Contains steps in the same order in which they were executed
+ /// Useful for tests
+ /// Tuples (step, step output)
+ executed_steps: RefCell, Box)>>,
+}
impl Cache {
/// Creates a new empty cache.
pub fn new() -> Cache {
- Cache(RefCell::new(HashMap::new()))
+ Cache::default()
}
/// Stores the result of a computation step in the cache.
pub fn put(&self, step: S, value: S::Output) {
- let mut cache = self.0.borrow_mut();
+ let mut cache = self.cache.borrow_mut();
let type_id = TypeId::of::();
let stepcache = cache
.entry(type_id)
@@ -234,12 +240,20 @@ pub fn put(&self, step: S, value: S::Output) {
.downcast_mut::>()
.expect("invalid type mapped");
assert!(!stepcache.contains_key(&step), "processing {step:?} a second time");
+
+ #[cfg(test)]
+ {
+ let step: Box = Box::new(step.clone());
+ let output: Box = Box::new(value.clone());
+ self.executed_steps.borrow_mut().push((step, output));
+ }
+
stepcache.insert(step, value);
}
/// Retrieves a cached result for the given step, if available.
pub fn get(&self, step: &S) -> Option {
- let mut cache = self.0.borrow_mut();
+ let mut cache = self.cache.borrow_mut();
let type_id = TypeId::of::();
let stepcache = cache
.entry(type_id)
@@ -252,8 +266,8 @@ pub fn get(&self, step: &S) -> Option {
#[cfg(test)]
impl Cache {
- pub fn all(&mut self) -> Vec<(S, S::Output)> {
- let cache = self.0.get_mut();
+ pub fn all(&mut self) -> Vec<(S, S::Output)> {
+ let cache = self.cache.get_mut();
let type_id = TypeId::of::();
let mut v = cache
.remove(&type_id)
@@ -265,7 +279,12 @@ pub fn all(&mut self) -> Vec<(S, S::Output)> {
}
pub fn contains(&self) -> bool {
- self.0.borrow().contains_key(&TypeId::of::())
+ self.cache.borrow().contains_key(&TypeId::of::())
+ }
+
+ #[cfg(test)]
+ pub fn into_executed_steps(mut self) -> Vec<(Box, Box)> {
+ mem::take(&mut self.executed_steps.borrow_mut())
}
}
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index 851bb38074ef..dcafeb80f90c 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -61,8 +61,8 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
///
/// This function determines which targets need a C compiler (and, if needed, a C++ compiler)
/// by combining the primary build target, host targets, and any additional targets. For
-/// each target, it calls [`find_target`] to configure the necessary compiler tools.
-pub fn find(build: &Build) {
+/// each target, it calls [`fill_target_compiler`] to configure the necessary compiler tools.
+pub fn fill_compilers(build: &mut Build) {
let targets: HashSet<_> = match build.config.cmd {
// We don't need to check cross targets for these commands.
crate::Subcommand::Clean { .. }
@@ -87,7 +87,7 @@ pub fn find(build: &Build) {
};
for target in targets.into_iter() {
- find_target(build, target);
+ fill_target_compiler(build, target);
}
}
@@ -96,7 +96,7 @@ pub fn find(build: &Build) {
/// This function uses both user-specified configuration (from `bootstrap.toml`) and auto-detection
/// logic to determine the correct C/C++ compilers for the target. It also determines the appropriate
/// archiver (`ar`) and sets up additional compilation flags (both handled and unhandled).
-pub fn find_target(build: &Build, target: TargetSelection) {
+pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) {
let mut cfg = new_cc_build(build, target);
let config = build.config.target_config.get(&target);
if let Some(cc) = config
@@ -113,7 +113,7 @@ pub fn find_target(build: &Build, target: TargetSelection) {
cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()
};
- build.cc.borrow_mut().insert(target, compiler.clone());
+ build.cc.insert(target, compiler.clone());
let mut cflags = build.cc_handled_clags(target, CLang::C);
cflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C));
@@ -135,7 +135,7 @@ pub fn find_target(build: &Build, target: TargetSelection) {
// for VxWorks, record CXX compiler which will be used in lib.rs:linker()
if cxx_configured || target.contains("vxworks") {
let compiler = cfg.get_compiler();
- build.cxx.borrow_mut().insert(target, compiler);
+ build.cxx.insert(target, compiler);
}
build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
@@ -148,11 +148,11 @@ pub fn find_target(build: &Build, target: TargetSelection) {
}
if let Some(ar) = ar {
build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
- build.ar.borrow_mut().insert(target, ar);
+ build.ar.insert(target, ar);
}
if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) {
- build.ranlib.borrow_mut().insert(target, ranlib);
+ build.ranlib.insert(target, ranlib);
}
}
@@ -221,7 +221,10 @@ fn default_compiler(
}
t if t.contains("-wasi") => {
- let root = PathBuf::from(std::env::var_os("WASI_SDK_PATH")?);
+ let root = build
+ .wasi_sdk_path
+ .as_ref()
+ .expect("WASI_SDK_PATH mut be configured for a -wasi target");
let compiler = match compiler {
Language::C => format!("{t}-clang"),
Language::CPlusPlus => format!("{t}-clang++"),
diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs
index 1f50738959fb..bed03c18aaad 100644
--- a/src/bootstrap/src/utils/cc_detect/tests.rs
+++ b/src/bootstrap/src/utils/cc_detect/tests.rs
@@ -77,11 +77,11 @@ fn test_new_cc_build() {
#[test]
fn test_default_compiler_wasi() {
- let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+ let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
let target = TargetSelection::from_user("wasm32-wasi");
let wasi_sdk = PathBuf::from("/wasi-sdk");
- // SAFETY: bootstrap tests run on a single thread
- unsafe { env::set_var("WASI_SDK_PATH", &wasi_sdk) };
+ build.wasi_sdk_path = Some(wasi_sdk.clone());
+
let mut cfg = cc::Build::new();
if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) {
let expected = {
@@ -94,10 +94,6 @@ fn test_default_compiler_wasi() {
"default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set"
);
}
- // SAFETY: bootstrap tests run on a single thread
- unsafe {
- env::remove_var("WASI_SDK_PATH");
- }
}
#[test]
@@ -119,18 +115,14 @@ fn test_find_target_with_config() {
target_config.ar = Some(PathBuf::from("dummy-ar"));
target_config.ranlib = Some(PathBuf::from("dummy-ranlib"));
build.config.target_config.insert(target.clone(), target_config);
- find_target(&build, target.clone());
- let binding = build.cc.borrow();
- let cc_tool = binding.get(&target).unwrap();
+ fill_target_compiler(&mut build, target.clone());
+ let cc_tool = build.cc.get(&target).unwrap();
assert_eq!(cc_tool.path(), &PathBuf::from("dummy-cc"));
- let binding = build.cxx.borrow();
- let cxx_tool = binding.get(&target).unwrap();
+ let cxx_tool = build.cxx.get(&target).unwrap();
assert_eq!(cxx_tool.path(), &PathBuf::from("dummy-cxx"));
- let binding = build.ar.borrow();
- let ar = binding.get(&target).unwrap();
+ let ar = build.ar.get(&target).unwrap();
assert_eq!(ar, &PathBuf::from("dummy-ar"));
- let binding = build.ranlib.borrow();
- let ranlib = binding.get(&target).unwrap();
+ let ranlib = build.ranlib.get(&target).unwrap();
assert_eq!(ranlib, &PathBuf::from("dummy-ranlib"));
}
@@ -139,12 +131,12 @@ fn test_find_target_without_config() {
let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
build.config.target_config.clear();
- find_target(&build, target.clone());
- assert!(build.cc.borrow().contains_key(&target));
+ fill_target_compiler(&mut build, target.clone());
+ assert!(build.cc.contains_key(&target));
if !target.triple.contains("vxworks") {
- assert!(build.cxx.borrow().contains_key(&target));
+ assert!(build.cxx.contains_key(&target));
}
- assert!(build.ar.borrow().contains_key(&target));
+ assert!(build.ar.contains_key(&target));
}
#[test]
@@ -154,8 +146,8 @@ fn test_find() {
let target2 = TargetSelection::from_user("x86_64-unknown-openbsd");
build.targets.push(target1.clone());
build.hosts.push(target2.clone());
- find(&build);
+ fill_compilers(&mut build);
for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.host_target)) {
- assert!(build.cc.borrow().contains_key(t), "CC not set for target {}", t.triple);
+ assert!(build.cc.contains_key(t), "CC not set for target {}", t.triple);
}
}
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 8b2f2dd431e1..f4be22f1e649 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -98,7 +98,7 @@ pub fn is_dylib(path: &Path) -> bool {
/// Return the path to the containing submodule if available.
pub fn submodule_path_of(builder: &Builder<'_>, path: &str) -> Option {
- let submodule_paths = build_helper::util::parse_gitmodules(&builder.src);
+ let submodule_paths = builder.submodule_paths();
submodule_paths.iter().find_map(|submodule_path| {
if path.starts_with(submodule_path) { Some(submodule_path.to_string()) } else { None }
})
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 561af34a4478..9c6b4a7615d8 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -6,6 +6,9 @@
#![allow(dead_code)]
+#[cfg(test)]
+mod tests;
+
use std::env;
use std::ffi::OsString;
use std::fs::OpenOptions;
diff --git a/src/bootstrap/src/utils/tests/shared_helpers_tests.rs b/src/bootstrap/src/utils/shared_helpers/tests.rs
similarity index 73%
rename from src/bootstrap/src/utils/tests/shared_helpers_tests.rs
rename to src/bootstrap/src/utils/shared_helpers/tests.rs
index 6c47e7f24387..559e9f70abd2 100644
--- a/src/bootstrap/src/utils/tests/shared_helpers_tests.rs
+++ b/src/bootstrap/src/utils/shared_helpers/tests.rs
@@ -1,10 +1,3 @@
-//! The `shared_helpers` module can't have its own tests submodule, because
-//! that would cause problems for the shim binaries that include it via
-//! `#[path]`, so instead those unit tests live here.
-//!
-//! To prevent tidy from complaining about this file not being named `tests.rs`,
-//! it lives inside a submodule directory named `tests`.
-
use crate::utils::shared_helpers::parse_value_from_args;
#[test]
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
index 73d55db994cc..73c500f6e369 100644
--- a/src/bootstrap/src/utils/tests/mod.rs
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -1,2 +1,3 @@
+//! This module contains shared utilities for bootstrap tests.
+
pub mod git;
-mod shared_helpers_tests;
diff --git a/src/build_helper/src/util.rs b/src/build_helper/src/util.rs
index 72c05c4c48ab..80dd6813d136 100644
--- a/src/build_helper/src/util.rs
+++ b/src/build_helper/src/util.rs
@@ -2,7 +2,6 @@
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::Command;
-use std::sync::OnceLock;
/// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
///
@@ -51,25 +50,20 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> {
}
/// Returns the submodule paths from the `.gitmodules` file in the given directory.
-pub fn parse_gitmodules(target_dir: &Path) -> &[String] {
- static SUBMODULES_PATHS: OnceLock> = OnceLock::new();
+pub fn parse_gitmodules(target_dir: &Path) -> Vec {
let gitmodules = target_dir.join(".gitmodules");
assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display());
- let init_submodules_paths = || {
- let file = File::open(gitmodules).unwrap();
+ let file = File::open(gitmodules).unwrap();
- let mut submodules_paths = vec![];
- for line in BufReader::new(file).lines().map_while(Result::ok) {
- let line = line.trim();
- if line.starts_with("path") {
- let actual_path = line.split(' ').last().expect("Couldn't get value of path");
- submodules_paths.push(actual_path.to_owned());
- }
+ let mut submodules_paths = vec![];
+ for line in BufReader::new(file).lines().map_while(Result::ok) {
+ let line = line.trim();
+ if line.starts_with("path") {
+ let actual_path = line.split(' ').last().expect("Couldn't get value of path");
+ submodules_paths.push(actual_path.to_owned());
}
+ }
- submodules_paths
- };
-
- SUBMODULES_PATHS.get_or_init(|| init_submodules_paths())
+ submodules_paths
}
diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
index 241199d3bafb..58e66fd637a2 100644
--- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
@@ -22,10 +22,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-RUN mkdir -p /config
-RUN echo "[rust]" > /config/nopt-std-config.toml
-RUN echo "optimize = false" >> /config/nopt-std-config.toml
-
ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
ARG SCRIPT_ARG
COPY scripts/stage_2_test_set1.sh /scripts/
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
index 1b57ae7c8da0..854c36ee01c1 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
@@ -22,12 +22,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-RUN mkdir -p /config
-RUN echo "[rust]" > /config/nopt-std-config.toml
-RUN echo "optimize = false" >> /config/nopt-std-config.toml
-
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
--disable-optimize-tests \
--set rust.test-compare-mode
-ENV SCRIPT python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std \
+ENV SCRIPT python3 ../x.py test --stage 1 --set rust.optimize=false library/std \
&& python3 ../x.py --stage 2 test
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index d6d9e0fb7736..217cf764afbb 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -300,7 +300,7 @@ auto:
env:
IMAGE: i686-gnu-nopt
DOCKER_SCRIPT: >-
- python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std &&
+ python3 ../x.py test --stage 1 --set rust.optimize=false library/std &&
/scripts/stage_2_test_set2.sh
<<: *job-linux-4c
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 68f7d14f57f0..e96c81d5b1d1 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -16,7 +16,7 @@
#![feature(unqualified_local_imports)]
#![feature(derive_coerce_pointee)]
#![feature(arbitrary_self_types)]
-#![feature(file_lock)]
+#![cfg_attr(bootstrap, feature(file_lock))]
// Configure clippy and other lints
#![allow(
clippy::collapsible_else_if,
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 2f30827c9336..9d5725773e64 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -2,7 +2,6 @@
#![feature(io_error_more)]
#![feature(io_error_uncategorized)]
-#![feature(file_lock)]
use std::collections::BTreeMap;
use std::ffi::OsString;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
index 543ac0619dd3..385c98ef8778 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
@@ -486,7 +486,7 @@ macro_rules! experimental {
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
INTERNAL_UNSTABLE
),
- // Do not const-check this function's body. It will always get replaced during CTFE.
+ // Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
rustc_attr!(
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
),
diff --git a/tests/ui-fulldeps/stable-mir/check_variant.rs b/tests/ui-fulldeps/stable-mir/check_variant.rs
new file mode 100644
index 000000000000..b0de3369830b
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_variant.rs
@@ -0,0 +1,183 @@
+//@ run-pass
+//! Test that users are able to use stable mir APIs to retrieve
+//! discriminant value and type for AdtDef and Coroutine variants
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ edition: 2024
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use std::io::Write;
+use std::ops::ControlFlow;
+
+use stable_mir::CrateItem;
+use stable_mir::crate_def::CrateDef;
+use stable_mir::mir::{AggregateKind, Rvalue, Statement, StatementKind};
+use stable_mir::ty::{IntTy, RigidTy, Ty};
+
+const CRATE_NAME: &str = "crate_variant_ty";
+
+/// Test if we can retrieve discriminant info for different types.
+fn test_def_tys() -> ControlFlow<()> {
+ check_adt_mono();
+ check_adt_poly();
+ check_adt_poly2();
+
+ ControlFlow::Continue(())
+}
+
+fn check_adt_mono() {
+ let mono = get_fn("mono").expect_body();
+
+ check_statement_is_aggregate_assign(
+ &mono.blocks[0].statements[0],
+ 0,
+ RigidTy::Int(IntTy::Isize),
+ );
+ check_statement_is_aggregate_assign(
+ &mono.blocks[1].statements[0],
+ 1,
+ RigidTy::Int(IntTy::Isize),
+ );
+ check_statement_is_aggregate_assign(
+ &mono.blocks[2].statements[0],
+ 2,
+ RigidTy::Int(IntTy::Isize),
+ );
+}
+
+fn check_adt_poly() {
+ let poly = get_fn("poly").expect_body();
+
+ check_statement_is_aggregate_assign(
+ &poly.blocks[0].statements[0],
+ 0,
+ RigidTy::Int(IntTy::Isize),
+ );
+ check_statement_is_aggregate_assign(
+ &poly.blocks[1].statements[0],
+ 1,
+ RigidTy::Int(IntTy::Isize),
+ );
+ check_statement_is_aggregate_assign(
+ &poly.blocks[2].statements[0],
+ 2,
+ RigidTy::Int(IntTy::Isize),
+ );
+}
+
+fn check_adt_poly2() {
+ let poly = get_fn("poly2").expect_body();
+
+ check_statement_is_aggregate_assign(
+ &poly.blocks[0].statements[0],
+ 0,
+ RigidTy::Int(IntTy::Isize),
+ );
+ check_statement_is_aggregate_assign(
+ &poly.blocks[1].statements[0],
+ 1,
+ RigidTy::Int(IntTy::Isize),
+ );
+ check_statement_is_aggregate_assign(
+ &poly.blocks[2].statements[0],
+ 2,
+ RigidTy::Int(IntTy::Isize),
+ );
+}
+
+fn get_fn(name: &str) -> CrateItem {
+ stable_mir::all_local_items().into_iter().find(|it| it.name().eq(name)).unwrap()
+}
+
+fn check_statement_is_aggregate_assign(
+ statement: &Statement,
+ expected_discr_val: u128,
+ expected_discr_ty: RigidTy,
+) {
+ if let Statement { kind: StatementKind::Assign(_, rvalue), .. } = statement
+ && let Rvalue::Aggregate(aggregate, _) = rvalue
+ && let AggregateKind::Adt(adt_def, variant_idx, ..) = aggregate
+ {
+ let discr = adt_def.discriminant_for_variant(*variant_idx);
+
+ assert_eq!(discr.val, expected_discr_val);
+ assert_eq!(discr.ty, Ty::from_rigid_kind(expected_discr_ty));
+ } else {
+ unreachable!("Unexpected statement");
+ }
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+ let path = "defs_ty_input.rs";
+ generate_input(&path).unwrap();
+ let args = &[
+ "rustc".to_string(),
+ "-Cpanic=abort".to_string(),
+ "--crate-name".to_string(),
+ CRATE_NAME.to_string(),
+ path.to_string(),
+ ];
+ run!(args, test_def_tys).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+ let mut file = std::fs::File::create(path)?;
+ write!(
+ file,
+ r#"
+ use std::hint::black_box;
+
+ enum Mono {{
+ A,
+ B(i32),
+ C {{ a: i32, b: u32 }},
+ }}
+
+ enum Poly {{
+ A,
+ B(T),
+ C {{ t: T }},
+ }}
+
+ pub fn main() {{
+ mono();
+ poly();
+ poly2::(1);
+ }}
+
+ fn mono() {{
+ black_box(Mono::A);
+ black_box(Mono::B(6));
+ black_box(Mono::C {{a: 1, b: 10 }});
+ }}
+
+ fn poly() {{
+ black_box(Poly::::A);
+ black_box(Poly::B(1i32));
+ black_box(Poly::C {{ t: 1i32 }});
+ }}
+
+ fn poly2(t: T) {{
+ black_box(Poly::::A);
+ black_box(Poly::B(t));
+ black_box(Poly::C {{ t: t }});
+ }}
+ "#
+ )?;
+ Ok(())
+}