diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index ecf9745b77945..8f33e0806cbce 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -57,6 +57,8 @@ pub fn provide(providers: &mut Providers) {
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
};
+ providers.hooks.validate_scalar_in_layout =
+ |tcx, scalar, layout| util::validate_scalar_in_layout(tcx, scalar, layout);
}
/// `rustc_driver::main` installs a handler that will set this to `true` if
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index a729d9325c84a..83d45b12cd746 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -1,9 +1,10 @@
use rustc_abi::{BackendRepr, FieldsShape, Scalar, Variants};
-use rustc_middle::bug;
+use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement,
};
-use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt};
+use rustc_middle::ty::{PseudoCanonicalInput, ScalarInt, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug, ty};
use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine};
use crate::interpret::{InterpCx, MemoryKind};
@@ -34,7 +35,7 @@ pub fn check_validity_requirement<'tcx>(
let layout_cx = LayoutCx::new(tcx, input.typing_env);
if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
- check_validity_requirement_strict(layout, &layout_cx, kind)
+ Ok(check_validity_requirement_strict(layout, &layout_cx, kind))
} else {
check_validity_requirement_lax(layout, &layout_cx, kind)
}
@@ -46,7 +47,7 @@ fn check_validity_requirement_strict<'tcx>(
ty: TyAndLayout<'tcx>,
cx: &LayoutCx<'tcx>,
kind: ValidityRequirement,
-) -> Result> {
+) -> bool {
let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.typing_env, machine);
@@ -69,14 +70,13 @@ fn check_validity_requirement_strict<'tcx>(
// due to this.
// The value we are validating is temporary and discarded at the end of this function, so
// there is no point in reseting provenance and padding.
- Ok(cx
- .validate_operand(
- &allocated.into(),
- /*recursive*/ false,
- /*reset_provenance_and_padding*/ false,
- )
- .discard_err()
- .is_some())
+ cx.validate_operand(
+ &allocated.into(),
+ /*recursive*/ false,
+ /*reset_provenance_and_padding*/ false,
+ )
+ .discard_err()
+ .is_some()
}
/// Implements the 'lax' (default) version of the [`check_validity_requirement`] checks; see that
@@ -168,3 +168,31 @@ fn check_validity_requirement_lax<'tcx>(
Ok(true)
}
+
+pub(crate) fn validate_scalar_in_layout<'tcx>(
+ tcx: TyCtxtAt<'tcx>,
+ scalar: ScalarInt,
+ ty: Ty<'tcx>,
+) -> bool {
+ let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
+
+ let typing_env = ty::TypingEnv::fully_monomorphized();
+ let mut cx = InterpCx::new(tcx.tcx, tcx.span, typing_env, machine);
+
+ let Ok(layout) = cx.layout_of(ty) else {
+ span_bug!(tcx.span, "could not compute layout of {scalar:?}:{ty:?}")
+ };
+ let allocated = cx
+ .allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
+ .expect("OOM: failed to allocate for uninit check");
+
+ cx.write_scalar(scalar, &allocated).unwrap();
+
+ cx.validate_operand(
+ &allocated.into(),
+ /*recursive*/ false,
+ /*reset_provenance_and_padding*/ false,
+ )
+ .discard_err()
+ .is_some()
+}
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 25a9dbb2c1117..5be5ee8d1ae97 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -8,6 +8,7 @@ mod type_name;
pub use self::alignment::{is_disaligned, is_within_packed};
pub use self::check_validity_requirement::check_validity_requirement;
+pub(crate) use self::check_validity_requirement::validate_scalar_in_layout;
pub use self::compare_types::{relate_types, sub_types};
pub use self::type_name::type_name;
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index 2be242364c111..9822eb23a2367 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -112,6 +112,10 @@ declare_hooks! {
hook save_dep_graph() -> ();
hook query_key_hash_verify_all() -> ();
+
+ /// Ensure the given scalar is valid for the given type.
+ /// This checks non-recursive runtime validity.
+ hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool;
}
#[cold]
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 6c8591dae895b..f603add3c1153 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1741,7 +1741,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
" as ",
)?;
}
- ty::Pat(base_ty, pat) => {
+ ty::Pat(base_ty, pat) if self.tcx().validate_scalar_in_layout(int, ty) => {
self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?;
p!(write(" is {pat:?}"));
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 20a728d6d5b2c..0aa61152330a7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -155,42 +155,41 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range_endpoint(
&mut self,
expr: Option<&'tcx hir::PatExpr<'tcx>>,
- ) -> Result<
- (Option>, Option>, Option),
- ErrorGuaranteed,
- > {
- match expr {
- None => Ok((None, None, None)),
- Some(expr) => {
- let (kind, ascr, inline_const) = match self.lower_lit(expr) {
- PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
- (subpattern.kind, None, def_id.as_local())
- }
- PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
- (subpattern.kind, None, None)
- }
- PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
- (kind, Some(ascription), None)
- }
- kind => (kind, None, None),
- };
- let value = match kind {
- PatKind::Constant { value } => value,
- PatKind::ExpandedConstant { subpattern, .. }
- if let PatKind::Constant { value } = subpattern.kind =>
- {
- value
- }
- _ => {
- let msg = format!(
- "found bad range pattern endpoint `{expr:?}` outside of error recovery"
- );
- return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+ // Out-parameters collecting extra data to be reapplied by the caller
+ ascriptions: &mut Vec>,
+ inline_consts: &mut Vec,
+ ) -> Result>, ErrorGuaranteed> {
+ let Some(expr) = expr else { return Ok(None) };
+
+ // Lower the endpoint into a temporary `PatKind` that will then be
+ // deconstructed to obtain the constant value and other data.
+ let mut kind: PatKind<'tcx> = self.lower_lit(expr);
+
+ // Unpeel any ascription or inline-const wrapper nodes.
+ loop {
+ match kind {
+ PatKind::AscribeUserType { ascription, subpattern } => {
+ ascriptions.push(ascription);
+ kind = subpattern.kind;
+ }
+ PatKind::ExpandedConstant { is_inline, def_id, subpattern } => {
+ if is_inline {
+ inline_consts.extend(def_id.as_local());
}
- };
- Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
+ kind = subpattern.kind;
+ }
+ _ => break,
}
}
+
+ // The unpeeled kind should now be a constant, giving us the endpoint value.
+ let PatKind::Constant { value } = kind else {
+ let msg =
+ format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
+ return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+ };
+
+ Ok(Some(PatRangeBoundary::Finite(value)))
}
/// Overflowing literals are linted against in a late pass. This is mostly fine, except when we
@@ -253,11 +252,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
self.tcx.dcx().span_bug(span, msg);
}
- let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?;
- let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?;
+ // Collect extra data while lowering the endpoints, to be reapplied later.
+ let mut ascriptions = vec![];
+ let mut inline_consts = vec![];
+
+ let mut lower_endpoint =
+ |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut inline_consts);
- let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity);
- let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity);
+ let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
+ let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty }));
@@ -298,13 +301,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// If we are handling a range with associated constants (e.g.
// `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
// constants somewhere. Have them on the range pattern.
- for ascription in [lo_ascr, hi_ascr].into_iter().flatten() {
+ for ascription in ascriptions {
kind = PatKind::AscribeUserType {
ascription,
subpattern: Box::new(Pat { span, ty, kind }),
};
}
- for def in [lo_inline, hi_inline].into_iter().flatten() {
+ for def in inline_consts {
kind = PatKind::ExpandedConstant {
def_id: def.to_def_id(),
is_inline: true,
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 9eab75b06961f..944c34385572d 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "The Rust Standard Library"
edition = "2021"
+autobenches = false
[lib]
crate-type = ["dylib", "rlib"]
@@ -130,6 +131,18 @@ name = "pipe-subprocess"
path = "tests/pipe_subprocess.rs"
harness = false
+[[test]]
+name = "sync"
+path = "tests/sync/lib.rs"
+
+[[test]]
+name = "floats"
+path = "tests/floats/lib.rs"
+
+[[test]]
+name = "thread_local"
+path = "tests/thread_local/lib.rs"
+
[[bench]]
name = "stdbenches"
path = "benches/lib.rs"
diff --git a/library/std/benches/lib.rs b/library/std/benches/lib.rs
index 1b21c230a0bf2..e749d9c0f7998 100644
--- a/library/std/benches/lib.rs
+++ b/library/std/benches/lib.rs
@@ -5,3 +5,5 @@
extern crate test;
mod hash;
+mod path;
+mod time;
diff --git a/library/std/benches/path.rs b/library/std/benches/path.rs
new file mode 100644
index 0000000000000..094c00894a8ee
--- /dev/null
+++ b/library/std/benches/path.rs
@@ -0,0 +1,114 @@
+use core::hint::black_box;
+use std::collections::{BTreeSet, HashSet};
+use std::hash::{DefaultHasher, Hash, Hasher};
+use std::path::*;
+
+#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
+fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
+ let prefix = "my/home";
+ let mut paths: Vec<_> =
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
+
+ paths.sort();
+
+ b.iter(|| {
+ black_box(paths.as_mut_slice()).sort_unstable();
+ });
+}
+
+#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
+fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
+ let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
+ let paths: Vec<_> =
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
+
+ let mut set = BTreeSet::new();
+
+ paths.iter().for_each(|p| {
+ set.insert(p.as_path());
+ });
+
+ b.iter(|| {
+ set.remove(paths[500].as_path());
+ set.insert(paths[500].as_path());
+ });
+}
+
+#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
+fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
+ let prefix = "my/home";
+ let paths: Vec<_> =
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
+
+ let mut set = BTreeSet::new();
+
+ paths.iter().for_each(|p| {
+ set.insert(p.as_path());
+ });
+
+ b.iter(|| {
+ set.remove(paths[500].as_path());
+ set.insert(paths[500].as_path());
+ });
+}
+
+#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
+fn bench_path_hashset(b: &mut test::Bencher) {
+ let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
+ let paths: Vec<_> =
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
+
+ let mut set = HashSet::new();
+
+ paths.iter().for_each(|p| {
+ set.insert(p.as_path());
+ });
+
+ b.iter(|| {
+ set.remove(paths[500].as_path());
+ set.insert(black_box(paths[500].as_path()))
+ });
+}
+
+#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
+fn bench_path_hashset_miss(b: &mut test::Bencher) {
+ let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
+ let paths: Vec<_> =
+ (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
+
+ let mut set = HashSet::new();
+
+ paths.iter().for_each(|p| {
+ set.insert(p.as_path());
+ });
+
+ let probe = PathBuf::from(prefix).join("other");
+
+ b.iter(|| set.remove(black_box(probe.as_path())));
+}
+
+#[bench]
+fn bench_hash_path_short(b: &mut test::Bencher) {
+ let mut hasher = DefaultHasher::new();
+ let path = Path::new("explorer.exe");
+
+ b.iter(|| black_box(path).hash(&mut hasher));
+
+ black_box(hasher.finish());
+}
+
+#[bench]
+fn bench_hash_path_long(b: &mut test::Bencher) {
+ let mut hasher = DefaultHasher::new();
+ let path =
+ Path::new("/aaaaa/aaaaaa/./../aaaaaaaa/bbbbbbbbbbbbb/ccccccccccc/ddddddddd/eeeeeee.fff");
+
+ b.iter(|| black_box(path).hash(&mut hasher));
+
+ black_box(hasher.finish());
+}
diff --git a/library/std/benches/time.rs b/library/std/benches/time.rs
new file mode 100644
index 0000000000000..552481cad928a
--- /dev/null
+++ b/library/std/benches/time.rs
@@ -0,0 +1,47 @@
+use std::time::Instant;
+
+#[cfg(not(target_arch = "wasm32"))]
+use test::{Bencher, black_box};
+
+macro_rules! bench_instant_threaded {
+ ($bench_name:ident, $thread_count:expr) => {
+ #[bench]
+ #[cfg(not(target_arch = "wasm32"))]
+ fn $bench_name(b: &mut Bencher) -> std::thread::Result<()> {
+ use std::sync::Arc;
+ use std::sync::atomic::{AtomicBool, Ordering};
+
+ let running = Arc::new(AtomicBool::new(true));
+
+ let threads: Vec<_> = (0..$thread_count)
+ .map(|_| {
+ let flag = Arc::clone(&running);
+ std::thread::spawn(move || {
+ while flag.load(Ordering::Relaxed) {
+ black_box(Instant::now());
+ }
+ })
+ })
+ .collect();
+
+ b.iter(|| {
+ let a = Instant::now();
+ let b = Instant::now();
+ assert!(b >= a);
+ });
+
+ running.store(false, Ordering::Relaxed);
+
+ for t in threads {
+ t.join()?;
+ }
+ Ok(())
+ }
+ };
+}
+
+bench_instant_threaded!(instant_contention_01_threads, 0);
+bench_instant_threaded!(instant_contention_02_threads, 1);
+bench_instant_threaded!(instant_contention_04_threads, 3);
+bench_instant_threaded!(instant_contention_08_threads, 7);
+bench_instant_threaded!(instant_contention_16_threads, 15);
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index bbd506127fb67..c665dfd36247f 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -10,9 +10,6 @@
#![stable(feature = "env", since = "1.0.0")]
-#[cfg(test)]
-mod tests;
-
use crate::error::Error;
use crate::ffi::{OsStr, OsString};
use crate::path::{Path, PathBuf};
diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs
deleted file mode 100644
index d021726106872..0000000000000
--- a/library/std/src/env/tests.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use super::*;
-
-#[test]
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)]
-fn test_self_exe_path() {
- let path = current_exe();
- assert!(path.is_ok());
- let path = path.unwrap();
-
- // Hard to test this function
- assert!(path.is_absolute());
-}
-
-#[test]
-fn test() {
- assert!((!Path::new("test-path").is_absolute()));
-
- #[cfg(not(target_env = "sgx"))]
- current_dir().unwrap();
-}
-
-#[test]
-#[cfg(windows)]
-fn split_paths_windows() {
- use crate::path::PathBuf;
-
- fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
- split_paths(unparsed).collect::>()
- == parsed.iter().map(|s| PathBuf::from(*s)).collect::>()
- }
-
- assert!(check_parse("", &mut [""]));
- assert!(check_parse(r#""""#, &mut [""]));
- assert!(check_parse(";;", &mut ["", "", ""]));
- assert!(check_parse(r"c:\", &mut [r"c:\"]));
- assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
- assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"]));
- assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
- assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
-}
-
-#[test]
-#[cfg(unix)]
-fn split_paths_unix() {
- use crate::path::PathBuf;
-
- fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
- split_paths(unparsed).collect::>()
- == parsed.iter().map(|s| PathBuf::from(*s)).collect::>()
- }
-
- assert!(check_parse("", &mut [""]));
- assert!(check_parse("::", &mut ["", "", ""]));
- assert!(check_parse("/", &mut ["/"]));
- assert!(check_parse("/:", &mut ["/", ""]));
- assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
-}
-
-#[test]
-#[cfg(unix)]
-fn join_paths_unix() {
- use crate::ffi::OsStr;
-
- fn test_eq(input: &[&str], output: &str) -> bool {
- &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
- }
-
- assert!(test_eq(&[], ""));
- assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin"));
- assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:"));
- assert!(join_paths(["/te:st"].iter().cloned()).is_err());
-}
-
-#[test]
-#[cfg(windows)]
-fn join_paths_windows() {
- use crate::ffi::OsStr;
-
- fn test_eq(input: &[&str], output: &str) -> bool {
- &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
- }
-
- assert!(test_eq(&[], ""));
- assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\"));
- assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;"));
- assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#));
- assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
-}
-
-#[test]
-fn args_debug() {
- assert_eq!(
- format!("Args {{ inner: {:?} }}", args().collect::>()),
- format!("{:?}", args())
- );
-}
-
-#[test]
-fn args_os_debug() {
- assert_eq!(
- format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()),
- format!("{:?}", args_os())
- );
-}
-
-#[test]
-fn vars_debug() {
- assert_eq!(
- format!("Vars {{ inner: {:?} }}", vars().collect::>()),
- format!("{:?}", vars())
- );
-}
-
-#[test]
-fn vars_os_debug() {
- assert_eq!(
- format!("VarsOs {{ inner: {:?} }}", vars_os().collect::>()),
- format!("{:?}", vars_os())
- );
-}
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index b3e63aaf1c567..def5f984c88e4 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -1,9 +1,6 @@
#![doc = include_str!("../../core/src/error.md")]
#![stable(feature = "rust1", since = "1.0.0")]
-#[cfg(test)]
-mod tests;
-
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::error::Error;
#[unstable(feature = "error_generic_member_access", issue = "99301")]
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index d65f5ed61cfbc..89612fa747551 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -4,9 +4,6 @@
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
-#[cfg(test)]
-mod tests;
-
#[unstable(feature = "f128", issue = "116909")]
pub use core::f128::consts;
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index 5b0903bceabb4..cc523c93b4de7 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -4,9 +4,6 @@
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
-#[cfg(test)]
-mod tests;
-
#[unstable(feature = "f16", issue = "116909")]
pub use core::f16::consts;
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index f9b6723788ae3..260c499b7f4b9 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -12,9 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
-#[cfg(test)]
-mod tests;
-
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated, deprecated_in_future)]
pub use core::f32::{
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 0de55a15d48e8..7af646f8cfd60 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -12,9 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
-#[cfg(test)]
-mod tests;
-
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated, deprecated_in_future)]
pub use core::f64::{
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 1b0d7f3dbf2c9..e0f9f0bb5cee4 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -372,18 +372,3 @@ macro_rules! dbg {
($($crate::dbg!($val)),+,)
};
}
-
-/// Verify that floats are within a tolerance of each other, 1.0e-6 by default.
-#[cfg(test)]
-macro_rules! assert_approx_eq {
- ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }};
- ($a:expr, $b:expr, $lim:expr) => {{
- let (a, b) = (&$a, &$b);
- let diff = (*a - *b).abs();
- assert!(
- diff < $lim,
- "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})",
- lim = $lim
- );
- }};
-}
diff --git a/library/std/src/num.rs b/library/std/src/num.rs
index d2f679e7dde54..ffb8789c906ef 100644
--- a/library/std/src/num.rs
+++ b/library/std/src/num.rs
@@ -6,9 +6,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
-#[cfg(test)]
-mod tests;
-
#[stable(feature = "int_error_matching", since = "1.55.0")]
pub use core::num::IntErrorKind;
#[stable(feature = "generic_nonzero", since = "1.79.0")]
@@ -29,28 +26,3 @@ pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError}
pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize};
#[stable(feature = "nonzero", since = "1.28.0")]
pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize};
-
-#[cfg(test)]
-use crate::fmt;
-#[cfg(test)]
-use crate::ops::{Add, Div, Mul, Rem, Sub};
-
-/// Helper function for testing numeric operations
-#[cfg(test)]
-pub fn test_num(ten: T, two: T)
-where
- T: PartialEq
- + Add
- + Sub
- + Mul
- + Div
- + Rem
- + fmt::Debug
- + Copy,
-{
- assert_eq!(ten.add(two), ten + two);
- assert_eq!(ten.sub(two), ten - two);
- assert_eq!(ten.mul(two), ten * two);
- assert_eq!(ten.div(two), ten / two);
- assert_eq!(ten.rem(two), ten % two);
-}
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index d649357a56d71..153189b8b0315 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -529,6 +529,3 @@ pub fn get_backtrace_style() -> Option {
Err(new) => BacktraceStyle::from_u8(new),
}
}
-
-#[cfg(test)]
-mod tests;
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 7fd08a97f1f20..97e17acadeac7 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -67,9 +67,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
-#[cfg(test)]
-mod tests;
-
use core::clone::CloneToUninit;
use crate::borrow::{Borrow, Cow};
diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs
index 862753e4765dc..067ff66d9af73 100644
--- a/library/std/src/sync/barrier.rs
+++ b/library/std/src/sync/barrier.rs
@@ -1,6 +1,3 @@
-#[cfg(test)]
-mod tests;
-
use crate::fmt;
// FIXME(nonpoison_mutex,nonpoison_condvar): switch to nonpoison versions once they are available
use crate::sync::{Condvar, Mutex};
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 98c83d8d326ca..78cf8841efefb 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -350,6 +350,3 @@ unsafe impl Sync for LazyLock {}
impl RefUnwindSafe for LazyLock {}
#[stable(feature = "lazy_cell", since = "1.80.0")]
impl UnwindSafe for LazyLock {}
-
-#[cfg(test)]
-mod tests;
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc.rs
similarity index 99%
rename from library/std/src/sync/mpsc/mod.rs
rename to library/std/src/sync/mpsc.rs
index c86b546e01169..f942937c14d11 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc.rs
@@ -137,12 +137,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
-mod tests;
-
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
-mod sync_tests;
-
// MPSC channels are built as a wrapper around MPMC channels, which
// were ported from the `crossbeam-channel` crate. MPMC channels are
// not exposed publicly, but if you are curious about the implementation,
@@ -737,9 +731,10 @@ impl SyncSender {
// Attempts to send for a value on this receiver, returning an error if the
// corresponding channel has hung up, or if it waits more than `timeout`.
//
- // This method is currently private and only used for tests.
- #[allow(unused)]
- fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError> {
+ // This method is currently only used for tests.
+ #[unstable(issue = "none", feature = "std_internals")]
+ #[doc(hidden)]
+ pub fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError> {
self.inner.send_timeout(t, timeout)
}
}
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index 6fc0abbed9e15..fdba802ecace7 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -674,6 +674,3 @@ unsafe impl<#[may_dangle] T> Drop for OnceLock {
}
}
}
-
-#[cfg(test)]
-mod tests;
diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs
index a6e2389c93baf..7f0f3f652bcb7 100644
--- a/library/std/src/sync/poison/condvar.rs
+++ b/library/std/src/sync/poison/condvar.rs
@@ -1,6 +1,3 @@
-#[cfg(test)]
-mod tests;
-
use crate::fmt;
use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex};
use crate::sys::sync as sys;
diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs
index fb43ada637543..9362c764173a8 100644
--- a/library/std/src/sync/poison/mutex.rs
+++ b/library/std/src/sync/poison/mutex.rs
@@ -1,6 +1,3 @@
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
-mod tests;
-
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::marker::PhantomData;
diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs
index 528b11ca0c1e6..d2938b7a0c12e 100644
--- a/library/std/src/sync/poison/once.rs
+++ b/library/std/src/sync/poison/once.rs
@@ -3,9 +3,6 @@
//! This primitive is meant to be used to run one-time initialization. An
//! example use case would be for initializing an FFI library.
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
-mod tests;
-
use crate::fmt;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sys::sync as sys;
diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs
index 1519baf99a8fd..f9d9321f5f2d8 100644
--- a/library/std/src/sync/poison/rwlock.rs
+++ b/library/std/src/sync/poison/rwlock.rs
@@ -1,6 +1,3 @@
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
-mod tests;
-
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::marker::PhantomData;
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index 0140e0d21299f..e009eb410efc0 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -1,6 +1,3 @@
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
-mod tests;
-
use cfg_if::cfg_if;
use crate::cell::UnsafeCell;
@@ -324,7 +321,10 @@ impl ReentrantLock {
/// Otherwise, an RAII guard is returned.
///
/// This function does not block.
- pub(crate) fn try_lock(&self) -> Option> {
+ // FIXME maybe make it a public part of the API?
+ #[unstable(issue = "none", feature = "std_internals")]
+ #[doc(hidden)]
+ pub fn try_lock(&self) -> Option> {
let this_thread = current_id();
// Safety: We only touch lock_count when we own the inner mutex.
// Additionally, we only call `self.owner.set()` while holding
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index c003503ca8b09..ca04aa4ada497 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -2,12 +2,6 @@
#![unstable(feature = "thread_local_internals", issue = "none")]
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
-mod tests;
-
-#[cfg(test)]
-mod dynamic_tests;
-
use crate::cell::{Cell, RefCell};
use crate::error::Error;
use crate::fmt;
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 9f4f8a0d0880c..88b3e9e0ceba0 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -31,9 +31,6 @@
#![stable(feature = "time", since = "1.3.0")]
-#[cfg(test)]
-mod tests;
-
#[stable(feature = "time", since = "1.3.0")]
pub use core::time::Duration;
#[stable(feature = "duration_checked_float", since = "1.66.0")]
diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs
index 44fe84c989fb7..e754cf8263b0f 100644
--- a/library/std/tests/env.rs
+++ b/library/std/tests/env.rs
@@ -1,163 +1,123 @@
use std::env::*;
-use std::ffi::{OsStr, OsString};
-
-use rand::distributions::{Alphanumeric, DistString};
+use std::path::Path;
mod common;
-use std::thread;
-
-use common::test_rng;
-
-#[track_caller]
-fn make_rand_name() -> OsString {
- let n = format!("TEST{}", Alphanumeric.sample_string(&mut test_rng(), 10));
- let n = OsString::from(n);
- assert!(var_os(&n).is_none());
- n
-}
-
-fn eq(a: Option, b: Option<&str>) {
- assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s));
-}
#[test]
-fn test_set_var() {
- let n = make_rand_name();
- set_var(&n, "VALUE");
- eq(var_os(&n), Some("VALUE"));
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)]
+fn test_self_exe_path() {
+ let path = current_exe();
+ assert!(path.is_ok());
+ let path = path.unwrap();
+
+ // Hard to test this function
+ assert!(path.is_absolute());
}
#[test]
-fn test_remove_var() {
- let n = make_rand_name();
- set_var(&n, "VALUE");
- remove_var(&n);
- eq(var_os(&n), None);
-}
+fn test() {
+ assert!((!Path::new("test-path").is_absolute()));
-#[test]
-fn test_set_var_overwrite() {
- let n = make_rand_name();
- set_var(&n, "1");
- set_var(&n, "2");
- eq(var_os(&n), Some("2"));
- set_var(&n, "");
- eq(var_os(&n), Some(""));
+ #[cfg(not(target_env = "sgx"))]
+ current_dir().unwrap();
}
#[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
-fn test_var_big() {
- let mut s = "".to_string();
- let mut i = 0;
- while i < 100 {
- s.push_str("aaaaaaaaaa");
- i += 1;
+#[cfg(windows)]
+fn split_paths_windows() {
+ use std::path::PathBuf;
+
+ fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+ split_paths(unparsed).collect::>()
+ == parsed.iter().map(|s| PathBuf::from(*s)).collect::>()
}
- let n = make_rand_name();
- set_var(&n, &s);
- eq(var_os(&n), Some(&s));
-}
-#[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
-fn test_env_set_get_huge() {
- let n = make_rand_name();
- let s = "x".repeat(10000);
- set_var(&n, &s);
- eq(var_os(&n), Some(&s));
- remove_var(&n);
- eq(var_os(&n), None);
+ assert!(check_parse("", &mut [""]));
+ assert!(check_parse(r#""""#, &mut [""]));
+ assert!(check_parse(";;", &mut ["", "", ""]));
+ assert!(check_parse(r"c:\", &mut [r"c:\"]));
+ assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
+ assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"]));
+ assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
+ assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
}
#[test]
-fn test_env_set_var() {
- let n = make_rand_name();
+#[cfg(unix)]
+fn split_paths_unix() {
+ use std::path::PathBuf;
- let mut e = vars_os();
- set_var(&n, "VALUE");
- assert!(!e.any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));
+ fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
+ split_paths(unparsed).collect::>()
+ == parsed.iter().map(|s| PathBuf::from(*s)).collect::>()
+ }
- assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));
+ assert!(check_parse("", &mut [""]));
+ assert!(check_parse("::", &mut ["", "", ""]));
+ assert!(check_parse("/", &mut ["/"]));
+ assert!(check_parse("/:", &mut ["/", ""]));
+ assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
}
#[test]
-#[cfg_attr(not(any(unix, windows)), ignore, allow(unused))]
-#[allow(deprecated)]
-fn env_home_dir() {
- use std::path::PathBuf;
+#[cfg(unix)]
+fn join_paths_unix() {
+ use std::ffi::OsStr;
- fn var_to_os_string(var: Result) -> Option {
- match var {
- Ok(var) => Some(OsString::from(var)),
- Err(VarError::NotUnicode(var)) => Some(var),
- _ => None,
- }
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
}
- cfg_if::cfg_if! {
- if #[cfg(unix)] {
- let oldhome = var_to_os_string(var("HOME"));
-
- set_var("HOME", "/home/MountainView");
- assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
-
- remove_var("HOME");
- if cfg!(target_os = "android") {
- assert!(home_dir().is_none());
- } else {
- // When HOME is not set, some platforms return `None`,
- // but others return `Some` with a default.
- // Just check that it is not "/home/MountainView".
- assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView")));
- }
-
- if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
- } else if #[cfg(windows)] {
- let oldhome = var_to_os_string(var("HOME"));
- let olduserprofile = var_to_os_string(var("USERPROFILE"));
-
- remove_var("HOME");
- remove_var("USERPROFILE");
-
- assert!(home_dir().is_some());
-
- set_var("HOME", "/home/PaloAlto");
- assert_ne!(home_dir(), Some(PathBuf::from("/home/PaloAlto")), "HOME must not be used");
+ assert!(test_eq(&[], ""));
+ assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin"));
+ assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:"));
+ assert!(join_paths(["/te:st"].iter().cloned()).is_err());
+}
- set_var("USERPROFILE", "/home/MountainView");
- assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+#[test]
+#[cfg(windows)]
+fn join_paths_windows() {
+ use std::ffi::OsStr;
- remove_var("HOME");
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output)
+ }
- assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+ assert!(test_eq(&[], ""));
+ assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\"));
+ assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;"));
+ assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#));
+ assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
+}
- set_var("USERPROFILE", "");
- assert_ne!(home_dir(), Some(PathBuf::from("")), "Empty USERPROFILE must be ignored");
+#[test]
+fn args_debug() {
+ assert_eq!(
+ format!("Args {{ inner: {:?} }}", args().collect::>()),
+ format!("{:?}", args())
+ );
+}
- remove_var("USERPROFILE");
+#[test]
+fn args_os_debug() {
+ assert_eq!(
+ format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()),
+ format!("{:?}", args_os())
+ );
+}
- if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
- if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); }
- }
- }
+#[test]
+fn vars_debug() {
+ assert_eq!(
+ format!("Vars {{ inner: {:?} }}", vars().collect::>()),
+ format!("{:?}", vars())
+ );
}
-#[test] // miri shouldn't detect any data race in this fn
-#[cfg_attr(any(not(miri), target_os = "emscripten"), ignore)]
-fn test_env_get_set_multithreaded() {
- let getter = thread::spawn(|| {
- for _ in 0..100 {
- let _ = var_os("foo");
- }
- });
-
- let setter = thread::spawn(|| {
- for _ in 0..100 {
- set_var("foo", "bar");
- }
- });
-
- let _ = getter.join();
- let _ = setter.join();
+#[test]
+fn vars_os_debug() {
+ assert_eq!(
+ format!("VarsOs {{ inner: {:?} }}", vars_os().collect::>()),
+ format!("{:?}", vars_os())
+ );
}
diff --git a/library/std/tests/env_modify.rs b/library/std/tests/env_modify.rs
new file mode 100644
index 0000000000000..6074744735005
--- /dev/null
+++ b/library/std/tests/env_modify.rs
@@ -0,0 +1,166 @@
+// These tests are in a separate integration test as they modify the environment,
+// and would otherwise cause some other tests to fail.
+
+use std::env::*;
+use std::ffi::{OsStr, OsString};
+
+use rand::distributions::{Alphanumeric, DistString};
+
+mod common;
+use std::thread;
+
+use common::test_rng;
+
+#[track_caller]
+fn make_rand_name() -> OsString {
+ let n = format!("TEST{}", Alphanumeric.sample_string(&mut test_rng(), 10));
+ let n = OsString::from(n);
+ assert!(var_os(&n).is_none());
+ n
+}
+
+fn eq(a: Option, b: Option<&str>) {
+ assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s));
+}
+
+#[test]
+fn test_set_var() {
+ let n = make_rand_name();
+ set_var(&n, "VALUE");
+ eq(var_os(&n), Some("VALUE"));
+}
+
+#[test]
+fn test_remove_var() {
+ let n = make_rand_name();
+ set_var(&n, "VALUE");
+ remove_var(&n);
+ eq(var_os(&n), None);
+}
+
+#[test]
+fn test_set_var_overwrite() {
+ let n = make_rand_name();
+ set_var(&n, "1");
+ set_var(&n, "2");
+ eq(var_os(&n), Some("2"));
+ set_var(&n, "");
+ eq(var_os(&n), Some(""));
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn test_var_big() {
+ let mut s = "".to_string();
+ let mut i = 0;
+ while i < 100 {
+ s.push_str("aaaaaaaaaa");
+ i += 1;
+ }
+ let n = make_rand_name();
+ set_var(&n, &s);
+ eq(var_os(&n), Some(&s));
+}
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn test_env_set_get_huge() {
+ let n = make_rand_name();
+ let s = "x".repeat(10000);
+ set_var(&n, &s);
+ eq(var_os(&n), Some(&s));
+ remove_var(&n);
+ eq(var_os(&n), None);
+}
+
+#[test]
+fn test_env_set_var() {
+ let n = make_rand_name();
+
+ let mut e = vars_os();
+ set_var(&n, "VALUE");
+ assert!(!e.any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));
+
+ assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));
+}
+
+#[test]
+#[cfg_attr(not(any(unix, windows)), ignore, allow(unused))]
+#[allow(deprecated)]
+fn env_home_dir() {
+ use std::path::PathBuf;
+
+ fn var_to_os_string(var: Result) -> Option {
+ match var {
+ Ok(var) => Some(OsString::from(var)),
+ Err(VarError::NotUnicode(var)) => Some(var),
+ _ => None,
+ }
+ }
+
+ cfg_if::cfg_if! {
+ if #[cfg(unix)] {
+ let oldhome = var_to_os_string(var("HOME"));
+
+ set_var("HOME", "/home/MountainView");
+ assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+
+ remove_var("HOME");
+ if cfg!(target_os = "android") {
+ assert!(home_dir().is_none());
+ } else {
+ // When HOME is not set, some platforms return `None`,
+ // but others return `Some` with a default.
+ // Just check that it is not "/home/MountainView".
+ assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+ }
+
+ if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
+ } else if #[cfg(windows)] {
+ let oldhome = var_to_os_string(var("HOME"));
+ let olduserprofile = var_to_os_string(var("USERPROFILE"));
+
+ remove_var("HOME");
+ remove_var("USERPROFILE");
+
+ assert!(home_dir().is_some());
+
+ set_var("HOME", "/home/PaloAlto");
+ assert_ne!(home_dir(), Some(PathBuf::from("/home/PaloAlto")), "HOME must not be used");
+
+ set_var("USERPROFILE", "/home/MountainView");
+ assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+
+ remove_var("HOME");
+
+ assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+
+ set_var("USERPROFILE", "");
+ assert_ne!(home_dir(), Some(PathBuf::from("")), "Empty USERPROFILE must be ignored");
+
+ remove_var("USERPROFILE");
+
+ if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
+ if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); }
+ }
+ }
+}
+
+#[test] // miri shouldn't detect any data race in this fn
+#[cfg_attr(any(not(miri), target_os = "emscripten"), ignore)]
+fn test_env_get_set_multithreaded() {
+ let getter = thread::spawn(|| {
+ for _ in 0..100 {
+ let _ = var_os("foo");
+ }
+ });
+
+ let setter = thread::spawn(|| {
+ for _ in 0..100 {
+ set_var("foo", "bar");
+ }
+ });
+
+ let _ = getter.join();
+ let _ = setter.join();
+}
diff --git a/library/std/src/error/tests.rs b/library/std/tests/error.rs
similarity index 98%
rename from library/std/src/error/tests.rs
rename to library/std/tests/error.rs
index 88a9f33c07908..8fd6eb3c02065 100644
--- a/library/std/src/error/tests.rs
+++ b/library/std/tests/error.rs
@@ -1,7 +1,8 @@
-use core::error::Request;
+#![feature(error_generic_member_access, error_reporter)]
-use super::Error;
-use crate::fmt;
+use std::backtrace::Backtrace;
+use std::error::{Error, Report, Request};
+use std::fmt;
#[derive(Debug, PartialEq)]
struct A;
@@ -38,9 +39,6 @@ fn downcasting() {
}
}
-use crate::backtrace::Backtrace;
-use crate::error::Report;
-
#[derive(Debug)]
struct SuperError {
source: SuperErrorSideKick,
diff --git a/library/std/src/f128/tests.rs b/library/std/tests/floats/f128.rs
similarity index 99%
rename from library/std/src/f128/tests.rs
rename to library/std/tests/floats/f128.rs
index cbcf9f96239bb..d0e8b157e6b6f 100644
--- a/library/std/src/f128/tests.rs
+++ b/library/std/tests/floats/f128.rs
@@ -1,11 +1,11 @@
// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy
#![cfg(reliable_f128)]
-use crate::f128::consts;
-use crate::num::FpCategory as Fp;
+use std::f128::consts;
+use std::num::FpCategory as Fp;
#[cfg(reliable_f128_math)]
-use crate::ops::Rem;
-use crate::ops::{Add, Div, Mul, Sub};
+use std::ops::Rem;
+use std::ops::{Add, Div, Mul, Sub};
// Note these tolerances make sense around zero, but not for more extreme exponents.
@@ -762,8 +762,6 @@ fn test_ln_gamma() {
#[test]
fn test_real_consts() {
- use super::consts;
-
let pi: f128 = consts::PI;
let frac_pi_2: f128 = consts::FRAC_PI_2;
let frac_pi_3: f128 = consts::FRAC_PI_3;
diff --git a/library/std/src/f16/tests.rs b/library/std/tests/floats/f16.rs
similarity index 99%
rename from library/std/src/f16/tests.rs
rename to library/std/tests/floats/f16.rs
index 684ee3f3855b8..5180f3d40f3a7 100644
--- a/library/std/src/f16/tests.rs
+++ b/library/std/tests/floats/f16.rs
@@ -1,8 +1,8 @@
// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy
#![cfg(reliable_f16)]
-use crate::f16::consts;
-use crate::num::{FpCategory as Fp, *};
+use std::f16::consts;
+use std::num::FpCategory as Fp;
/// Tolerance for results on the order of 10.0e-2
#[allow(unused)]
@@ -54,7 +54,7 @@ macro_rules! assert_f16_biteq {
#[test]
fn test_num_f16() {
- test_num(10f16, 2f16);
+ crate::test_num(10f16, 2f16);
}
#[test]
@@ -734,7 +734,6 @@ fn test_ln_gamma() {
#[test]
fn test_real_consts() {
// FIXME(f16_f128): add math tests when available
- use super::consts;
let pi: f16 = consts::PI;
let frac_pi_2: f16 = consts::FRAC_PI_2;
diff --git a/library/std/src/f32/tests.rs b/library/std/tests/floats/f32.rs
similarity index 99%
rename from library/std/src/f32/tests.rs
rename to library/std/tests/floats/f32.rs
index 99cfcfb231dad..bf7641986ada8 100644
--- a/library/std/src/f32/tests.rs
+++ b/library/std/tests/floats/f32.rs
@@ -1,5 +1,5 @@
-use crate::f32::consts;
-use crate::num::{FpCategory as Fp, *};
+use std::f32::consts;
+use std::num::FpCategory as Fp;
/// Smallest number
const TINY_BITS: u32 = 0x1;
@@ -35,7 +35,7 @@ macro_rules! assert_f32_biteq {
#[test]
fn test_num_f32() {
- test_num(10f32, 2f32);
+ crate::test_num(10f32, 2f32);
}
#[test]
@@ -700,8 +700,6 @@ fn test_ln_gamma() {
#[test]
fn test_real_consts() {
- use super::consts;
-
let pi: f32 = consts::PI;
let frac_pi_2: f32 = consts::FRAC_PI_2;
let frac_pi_3: f32 = consts::FRAC_PI_3;
diff --git a/library/std/src/f64/tests.rs b/library/std/tests/floats/f64.rs
similarity index 99%
rename from library/std/src/f64/tests.rs
rename to library/std/tests/floats/f64.rs
index f5ba2c7b594e9..cbbfcd15efd26 100644
--- a/library/std/src/f64/tests.rs
+++ b/library/std/tests/floats/f64.rs
@@ -1,5 +1,5 @@
-use crate::f64::consts;
-use crate::num::{FpCategory as Fp, *};
+use std::f64::consts;
+use std::num::FpCategory as Fp;
/// Smallest number
const TINY_BITS: u64 = 0x1;
@@ -35,7 +35,7 @@ macro_rules! assert_f64_biteq {
#[test]
fn test_num_f64() {
- test_num(10f64, 2f64);
+ crate::test_num(10f64, 2f64);
}
#[test]
@@ -680,7 +680,6 @@ fn test_ln_gamma() {
#[test]
fn test_real_consts() {
- use super::consts;
let pi: f64 = consts::PI;
let frac_pi_2: f64 = consts::FRAC_PI_2;
let frac_pi_3: f64 = consts::FRAC_PI_3;
diff --git a/library/std/tests/floats/lib.rs b/library/std/tests/floats/lib.rs
new file mode 100644
index 0000000000000..ad82f1a44e711
--- /dev/null
+++ b/library/std/tests/floats/lib.rs
@@ -0,0 +1,42 @@
+#![feature(f16, f128, float_gamma, float_minimum_maximum)]
+
+use std::fmt;
+use std::ops::{Add, Div, Mul, Rem, Sub};
+
+/// Verify that floats are within a tolerance of each other, 1.0e-6 by default.
+macro_rules! assert_approx_eq {
+ ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }};
+ ($a:expr, $b:expr, $lim:expr) => {{
+ let (a, b) = (&$a, &$b);
+ let diff = (*a - *b).abs();
+ assert!(
+ diff < $lim,
+ "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})",
+ lim = $lim
+ );
+ }};
+}
+
+/// Helper function for testing numeric operations
+pub fn test_num(ten: T, two: T)
+where
+ T: PartialEq
+ + Add
+ + Sub
+ + Mul
+ + Div
+ + Rem
+ + fmt::Debug
+ + Copy,
+{
+ assert_eq!(ten.add(two), ten + two);
+ assert_eq!(ten.sub(two), ten - two);
+ assert_eq!(ten.mul(two), ten * two);
+ assert_eq!(ten.div(two), ten / two);
+ assert_eq!(ten.rem(two), ten % two);
+}
+
+mod f128;
+mod f16;
+mod f32;
+mod f64;
diff --git a/library/std/src/num/tests.rs b/library/std/tests/num.rs
similarity index 98%
rename from library/std/src/num/tests.rs
rename to library/std/tests/num.rs
index df0df3f23f756..a7400f1c02df0 100644
--- a/library/std/src/num/tests.rs
+++ b/library/std/tests/num.rs
@@ -1,4 +1,4 @@
-use crate::ops::Mul;
+use std::ops::Mul;
#[test]
fn test_saturating_add_uint() {
@@ -190,8 +190,8 @@ fn test_uint_to_str_overflow() {
assert_eq!(u64_val.to_string(), "0");
}
-fn from_str(t: &str) -> Option {
- crate::str::FromStr::from_str(t).ok()
+fn from_str(t: &str) -> Option {
+ std::str::FromStr::from_str(t).ok()
}
#[test]
diff --git a/library/std/src/panic/tests.rs b/library/std/tests/panic.rs
similarity index 89%
rename from library/std/src/panic/tests.rs
rename to library/std/tests/panic.rs
index b37d74011cc67..f13b931dd222e 100644
--- a/library/std/src/panic/tests.rs
+++ b/library/std/tests/panic.rs
@@ -1,9 +1,9 @@
#![allow(dead_code)]
-use crate::cell::RefCell;
-use crate::panic::{AssertUnwindSafe, UnwindSafe};
-use crate::rc::Rc;
-use crate::sync::{Arc, Mutex, RwLock};
+use std::cell::RefCell;
+use std::panic::{AssertUnwindSafe, UnwindSafe};
+use std::rc::Rc;
+use std::sync::{Arc, Mutex, RwLock};
struct Foo {
a: i32,
diff --git a/library/std/src/path/tests.rs b/library/std/tests/path.rs
similarity index 93%
rename from library/std/src/path/tests.rs
rename to library/std/tests/path.rs
index 3f96ac4672aff..978402b6fdaea 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/tests/path.rs
@@ -1,10 +1,19 @@
-use core::hint::black_box;
-
-use super::*;
-use crate::collections::{BTreeSet, HashSet};
-use crate::hash::DefaultHasher;
-use crate::mem::MaybeUninit;
-use crate::ptr;
+#![feature(
+ clone_to_uninit,
+ path_add_extension,
+ path_file_prefix,
+ maybe_uninit_slice,
+ os_string_pathbuf_leak
+)]
+
+use std::clone::CloneToUninit;
+use std::ffi::OsStr;
+use std::hash::{DefaultHasher, Hash, Hasher};
+use std::mem::MaybeUninit;
+use std::path::*;
+use std::ptr;
+use std::rc::Rc;
+use std::sync::Arc;
#[allow(unknown_lints, unused_macro_rules)]
macro_rules! t (
@@ -110,7 +119,7 @@ macro_rules! t (
#[test]
fn into() {
- use crate::borrow::Cow;
+ use std::borrow::Cow;
let static_path = Path::new("/home/foo");
let static_cow_path: Cow<'static, Path> = static_path.into();
@@ -1525,7 +1534,7 @@ pub fn test_with_added_extension() {
#[test]
fn test_eq_receivers() {
- use crate::borrow::Cow;
+ use std::borrow::Cow;
let borrowed: &Path = Path::new("foo/bar");
let mut owned: PathBuf = PathBuf::new();
@@ -1550,7 +1559,7 @@ fn test_eq_receivers() {
#[test]
pub fn test_compare() {
- use crate::hash::{DefaultHasher, Hash, Hasher};
+ use std::hash::{DefaultHasher, Hash, Hasher};
fn hash(t: T) -> u64 {
let mut s = DefaultHasher::new();
@@ -1867,12 +1876,12 @@ fn test_ord() {
#[test]
#[cfg(any(unix, target_os = "wasi"))]
fn test_unix_absolute() {
- use crate::path::absolute;
+ use std::path::absolute;
assert!(absolute("").is_err());
let relative = "a/b";
- let mut expected = crate::env::current_dir().unwrap();
+ let mut expected = std::env::current_dir().unwrap();
expected.push(relative);
assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str());
@@ -1888,7 +1897,7 @@ fn test_unix_absolute() {
);
// Test leading `.` and `..` components
- let curdir = crate::env::current_dir().unwrap();
+ let curdir = std::env::current_dir().unwrap();
assert_eq!(absolute("./a").unwrap().as_os_str(), curdir.join("a").as_os_str());
assert_eq!(absolute("../a").unwrap().as_os_str(), curdir.join("../a").as_os_str()); // return /pwd/../a
}
@@ -1896,12 +1905,12 @@ fn test_unix_absolute() {
#[test]
#[cfg(windows)]
fn test_windows_absolute() {
- use crate::path::absolute;
+ use std::path::absolute;
// An empty path is an error.
assert!(absolute("").is_err());
let relative = r"a\b";
- let mut expected = crate::env::current_dir().unwrap();
+ let mut expected = std::env::current_dir().unwrap();
expected.push(relative);
assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str());
@@ -1953,116 +1962,6 @@ fn test_extension_path_sep_alternate() {
assert_eq!(path, Path::new("path/to/file.d\\test"));
}
-#[bench]
-#[cfg_attr(miri, ignore)] // Miri isn't fast...
-fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
- let prefix = "my/home";
- let mut paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
-
- paths.sort();
-
- b.iter(|| {
- black_box(paths.as_mut_slice()).sort_unstable();
- });
-}
-
-#[bench]
-#[cfg_attr(miri, ignore)] // Miri isn't fast...
-fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
- let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
- let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
-
- let mut set = BTreeSet::new();
-
- paths.iter().for_each(|p| {
- set.insert(p.as_path());
- });
-
- b.iter(|| {
- set.remove(paths[500].as_path());
- set.insert(paths[500].as_path());
- });
-}
-
-#[bench]
-#[cfg_attr(miri, ignore)] // Miri isn't fast...
-fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
- let prefix = "my/home";
- let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
-
- let mut set = BTreeSet::new();
-
- paths.iter().for_each(|p| {
- set.insert(p.as_path());
- });
-
- b.iter(|| {
- set.remove(paths[500].as_path());
- set.insert(paths[500].as_path());
- });
-}
-
-#[bench]
-#[cfg_attr(miri, ignore)] // Miri isn't fast...
-fn bench_path_hashset(b: &mut test::Bencher) {
- let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
- let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
-
- let mut set = HashSet::new();
-
- paths.iter().for_each(|p| {
- set.insert(p.as_path());
- });
-
- b.iter(|| {
- set.remove(paths[500].as_path());
- set.insert(black_box(paths[500].as_path()))
- });
-}
-
-#[bench]
-#[cfg_attr(miri, ignore)] // Miri isn't fast...
-fn bench_path_hashset_miss(b: &mut test::Bencher) {
- let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
- let paths: Vec<_> =
- (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
-
- let mut set = HashSet::new();
-
- paths.iter().for_each(|p| {
- set.insert(p.as_path());
- });
-
- let probe = PathBuf::from(prefix).join("other");
-
- b.iter(|| set.remove(black_box(probe.as_path())));
-}
-
-#[bench]
-fn bench_hash_path_short(b: &mut test::Bencher) {
- let mut hasher = DefaultHasher::new();
- let path = Path::new("explorer.exe");
-
- b.iter(|| black_box(path).hash(&mut hasher));
-
- black_box(hasher.finish());
-}
-
-#[bench]
-fn bench_hash_path_long(b: &mut test::Bencher) {
- let mut hasher = DefaultHasher::new();
- let path =
- Path::new("/aaaaa/aaaaaa/./../aaaaaaaa/bbbbbbbbbbbbb/ccccccccccc/ddddddddd/eeeeeee.fff");
-
- b.iter(|| black_box(path).hash(&mut hasher));
-
- black_box(hasher.finish());
-}
-
#[test]
fn clone_to_uninit() {
let a = Path::new("hello.txt");
diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/tests/sync/barrier.rs
similarity index 89%
rename from library/std/src/sync/barrier/tests.rs
rename to library/std/tests/sync/barrier.rs
index 0fbcd9988127b..8aefff9d5071c 100644
--- a/library/std/src/sync/barrier/tests.rs
+++ b/library/std/tests/sync/barrier.rs
@@ -1,6 +1,6 @@
-use crate::sync::mpsc::{TryRecvError, channel};
-use crate::sync::{Arc, Barrier};
-use crate::thread;
+use std::sync::mpsc::{TryRecvError, channel};
+use std::sync::{Arc, Barrier};
+use std::thread;
#[test]
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
diff --git a/library/std/src/sync/poison/condvar/tests.rs b/library/std/tests/sync/condvar.rs
similarity index 97%
rename from library/std/src/sync/poison/condvar/tests.rs
rename to library/std/tests/sync/condvar.rs
index f9e9066bc92a2..834de6bb1c295 100644
--- a/library/std/src/sync/poison/condvar/tests.rs
+++ b/library/std/tests/sync/condvar.rs
@@ -1,8 +1,8 @@
-use crate::sync::atomic::{AtomicBool, Ordering};
-use crate::sync::mpsc::channel;
-use crate::sync::{Arc, Condvar, Mutex};
-use crate::thread;
-use crate::time::Duration;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::mpsc::channel;
+use std::sync::{Arc, Condvar, Mutex};
+use std::thread;
+use std::time::Duration;
#[test]
fn smoke() {
diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/tests/sync/lazy_lock.rs
similarity index 93%
rename from library/std/src/sync/lazy_lock/tests.rs
rename to library/std/tests/sync/lazy_lock.rs
index 7d7dde5434990..6c14b79f2ce7c 100644
--- a/library/std/src/sync/lazy_lock/tests.rs
+++ b/library/std/tests/sync/lazy_lock.rs
@@ -1,8 +1,8 @@
-use crate::cell::LazyCell;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sync::{LazyLock, Mutex, OnceLock};
-use crate::{panic, thread};
+use std::cell::LazyCell;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::SeqCst;
+use std::sync::{LazyLock, Mutex, OnceLock};
+use std::{panic, thread};
fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R {
thread::spawn(f).join().unwrap()
@@ -149,7 +149,7 @@ fn is_sync_send() {
#[should_panic = "has previously been poisoned"]
fn lazy_force_mut_panic() {
let mut lazy = LazyLock::::new(|| panic!());
- crate::panic::catch_unwind(crate::panic::AssertUnwindSafe(|| {
+ panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = LazyLock::force_mut(&mut lazy);
}))
.unwrap_err();
diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs
new file mode 100644
index 0000000000000..51190f0894fb7
--- /dev/null
+++ b/library/std/tests/sync/lib.rs
@@ -0,0 +1,31 @@
+#![feature(lazy_get)]
+#![feature(mapped_lock_guards)]
+#![feature(mpmc_channel)]
+#![feature(once_cell_try)]
+#![feature(lock_value_accessors)]
+#![feature(reentrant_lock)]
+#![feature(rwlock_downgrade)]
+#![feature(std_internals)]
+#![allow(internal_features)]
+
+mod barrier;
+mod condvar;
+mod lazy_lock;
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod mpmc;
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod mpsc;
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod mpsc_sync;
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod mutex;
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod once;
+mod once_lock;
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod reentrant_lock;
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod rwlock;
+
+#[path = "../common/mod.rs"]
+mod common;
diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/tests/sync/mpmc.rs
similarity index 99%
rename from library/std/src/sync/mpmc/tests.rs
rename to library/std/tests/sync/mpmc.rs
index ab14050df6c98..81b92297f76a3 100644
--- a/library/std/src/sync/mpmc/tests.rs
+++ b/library/std/tests/sync/mpmc.rs
@@ -1,5 +1,6 @@
-use super::*;
-use crate::{env, thread};
+use std::sync::mpmc::*;
+use std::time::{Duration, Instant};
+use std::{env, thread};
pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/tests/sync/mpsc.rs
similarity index 99%
rename from library/std/src/sync/mpsc/tests.rs
rename to library/std/tests/sync/mpsc.rs
index 13892fa0d18e4..1d8edfde44bed 100644
--- a/library/std/src/sync/mpsc/tests.rs
+++ b/library/std/tests/sync/mpsc.rs
@@ -1,5 +1,6 @@
-use super::*;
-use crate::{env, thread};
+use std::sync::mpsc::*;
+use std::time::{Duration, Instant};
+use std::{env, thread};
pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/tests/sync/mpsc_sync.rs
similarity index 99%
rename from library/std/src/sync/mpsc/sync_tests.rs
rename to library/std/tests/sync/mpsc_sync.rs
index 49b65c8efe692..a7f326d201b00 100644
--- a/library/std/src/sync/mpsc/sync_tests.rs
+++ b/library/std/tests/sync/mpsc_sync.rs
@@ -1,7 +1,8 @@
-use super::*;
-use crate::rc::Rc;
-use crate::sync::mpmc::SendTimeoutError;
-use crate::{env, thread};
+use std::rc::Rc;
+use std::sync::mpmc::SendTimeoutError;
+use std::sync::mpsc::*;
+use std::time::Duration;
+use std::{env, thread};
pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
diff --git a/library/std/src/sync/poison/mutex/tests.rs b/library/std/tests/sync/mutex.rs
similarity index 97%
rename from library/std/src/sync/poison/mutex/tests.rs
rename to library/std/tests/sync/mutex.rs
index 395c8aada089a..74c627201073e 100644
--- a/library/std/src/sync/poison/mutex/tests.rs
+++ b/library/std/tests/sync/mutex.rs
@@ -1,10 +1,10 @@
-use crate::fmt::Debug;
-use crate::ops::FnMut;
-use crate::panic::{self, AssertUnwindSafe};
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sync::mpsc::channel;
-use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
-use crate::{hint, mem, thread};
+use std::fmt::Debug;
+use std::ops::FnMut;
+use std::panic::{self, AssertUnwindSafe};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::mpsc::channel;
+use std::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
+use std::{hint, mem, thread};
struct Packet(Arc<(Mutex, Condvar)>);
diff --git a/library/std/src/sync/poison/once/tests.rs b/library/std/tests/sync/once.rs
similarity index 94%
rename from library/std/src/sync/poison/once/tests.rs
rename to library/std/tests/sync/once.rs
index ce96468aeb6e1..a3ffc73fe06b9 100644
--- a/library/std/src/sync/poison/once/tests.rs
+++ b/library/std/tests/sync/once.rs
@@ -1,9 +1,9 @@
-use super::Once;
-use crate::sync::atomic::AtomicBool;
-use crate::sync::atomic::Ordering::Relaxed;
-use crate::sync::mpsc::channel;
-use crate::time::Duration;
-use crate::{panic, thread};
+use std::sync::Once;
+use std::sync::atomic::AtomicBool;
+use std::sync::atomic::Ordering::Relaxed;
+use std::sync::mpsc::channel;
+use std::time::Duration;
+use std::{panic, thread};
#[test]
fn smoke_once() {
diff --git a/library/std/src/sync/once_lock/tests.rs b/library/std/tests/sync/once_lock.rs
similarity index 91%
rename from library/std/src/sync/once_lock/tests.rs
rename to library/std/tests/sync/once_lock.rs
index 5113d436c3c99..ac9aaa8892eff 100644
--- a/library/std/src/sync/once_lock/tests.rs
+++ b/library/std/tests/sync/once_lock.rs
@@ -1,8 +1,8 @@
-use crate::sync::OnceLock;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sync::mpsc::channel;
-use crate::{panic, thread};
+use std::sync::OnceLock;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::SeqCst;
+use std::sync::mpsc::channel;
+use std::{panic, thread};
fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R {
thread::spawn(f).join().unwrap()
@@ -33,15 +33,6 @@ fn sync_once_cell_get_mut() {
assert_eq!(c.get_mut(), Some(&mut 92));
}
-#[test]
-fn sync_once_cell_get_unchecked() {
- let c = OnceLock::new();
- c.set(92).unwrap();
- unsafe {
- assert_eq!(c.get_unchecked(), &92);
- }
-}
-
#[test]
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
fn sync_once_cell_drop() {
@@ -88,7 +79,6 @@ fn get_or_try_init() {
let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
assert!(res.is_err());
- assert!(!cell.is_initialized());
assert!(cell.get().is_none());
assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
@@ -174,7 +164,7 @@ fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
break;
}
#[cfg(target_env = "sgx")]
- crate::thread::yield_now();
+ std::thread::yield_now();
}
});
}
diff --git a/library/std/src/sync/reentrant_lock/tests.rs b/library/std/tests/sync/reentrant_lock.rs
similarity index 91%
rename from library/std/src/sync/reentrant_lock/tests.rs
rename to library/std/tests/sync/reentrant_lock.rs
index aeef0289d28f8..2b7b87e36234a 100644
--- a/library/std/src/sync/reentrant_lock/tests.rs
+++ b/library/std/tests/sync/reentrant_lock.rs
@@ -1,7 +1,6 @@
-use super::ReentrantLock;
-use crate::cell::RefCell;
-use crate::sync::Arc;
-use crate::thread;
+use std::cell::RefCell;
+use std::sync::{Arc, ReentrantLock};
+use std::thread;
#[test]
fn smoke() {
diff --git a/library/std/src/sync/poison/rwlock/tests.rs b/library/std/tests/sync/rwlock.rs
similarity index 98%
rename from library/std/src/sync/poison/rwlock/tests.rs
rename to library/std/tests/sync/rwlock.rs
index 057c2f1a5d7a7..bd4bc7a14bc8e 100644
--- a/library/std/src/sync/poison/rwlock/tests.rs
+++ b/library/std/tests/sync/rwlock.rs
@@ -1,15 +1,15 @@
-use rand::Rng;
-
-use crate::fmt::Debug;
-use crate::ops::FnMut;
-use crate::panic::{self, AssertUnwindSafe};
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sync::mpsc::channel;
-use crate::sync::{
+use std::fmt::Debug;
+use std::ops::FnMut;
+use std::panic::{self, AssertUnwindSafe};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::mpsc::channel;
+use std::sync::{
Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
TryLockError,
};
-use crate::{hint, mem, thread};
+use std::{hint, mem, thread};
+
+use rand::Rng;
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
@@ -57,7 +57,7 @@ fn frob() {
let tx = tx.clone();
let r = r.clone();
thread::spawn(move || {
- let mut rng = crate::test_helpers::test_rng();
+ let mut rng = crate::common::test_rng();
for _ in 0..M {
if rng.gen_bool(1.0 / (N as f64)) {
drop(r.write().unwrap());
@@ -704,7 +704,7 @@ fn test_downgrade_atomic() {
// Wait for a good amount of time so that evil threads go to sleep.
// Note: this is not strictly necessary...
- let eternity = crate::time::Duration::from_millis(42);
+ let eternity = std::time::Duration::from_millis(42);
thread::sleep(eternity);
// Once everyone is asleep, set the value to `NEW_VALUE`.
diff --git a/library/std/src/thread/local/dynamic_tests.rs b/library/std/tests/thread_local/dynamic_tests.rs
similarity index 89%
rename from library/std/src/thread/local/dynamic_tests.rs
rename to library/std/tests/thread_local/dynamic_tests.rs
index dd18004164824..454462b392510 100644
--- a/library/std/src/thread/local/dynamic_tests.rs
+++ b/library/std/tests/thread_local/dynamic_tests.rs
@@ -1,6 +1,6 @@
-use crate::cell::RefCell;
-use crate::collections::HashMap;
-use crate::thread_local;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::thread_local;
#[test]
fn smoke() {
diff --git a/library/std/tests/thread_local/lib.rs b/library/std/tests/thread_local/lib.rs
new file mode 100644
index 0000000000000..c52914354253c
--- /dev/null
+++ b/library/std/tests/thread_local/lib.rs
@@ -0,0 +1,4 @@
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))]
+mod tests;
+
+mod dynamic_tests;
diff --git a/library/std/src/thread/local/tests.rs b/library/std/tests/thread_local/tests.rs
similarity index 98%
rename from library/std/src/thread/local/tests.rs
rename to library/std/tests/thread_local/tests.rs
index 9d4f52a09218e..aa020c2559cc5 100644
--- a/library/std/src/thread/local/tests.rs
+++ b/library/std/tests/thread_local/tests.rs
@@ -1,8 +1,8 @@
-use crate::cell::{Cell, UnsafeCell};
-use crate::sync::atomic::{AtomicU8, Ordering};
-use crate::sync::{Arc, Condvar, Mutex};
-use crate::thread::{self, Builder, LocalKey};
-use crate::thread_local;
+use std::cell::{Cell, UnsafeCell};
+use std::sync::atomic::{AtomicU8, Ordering};
+use std::sync::{Arc, Condvar, Mutex};
+use std::thread::{self, Builder, LocalKey};
+use std::thread_local;
#[derive(Clone, Default)]
struct Signal(Arc<(Mutex, Condvar)>);
diff --git a/library/std/src/time/tests.rs b/library/std/tests/time.rs
similarity index 81%
rename from library/std/src/time/tests.rs
rename to library/std/tests/time.rs
index e88f2d5e80676..40709eae37cfc 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/tests/time.rs
@@ -1,9 +1,7 @@
-use core::fmt::Debug;
+#![feature(duration_constants)]
-#[cfg(not(target_arch = "wasm32"))]
-use test::{Bencher, black_box};
-
-use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
+use std::fmt::Debug;
+use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
macro_rules! assert_almost_eq {
($a:expr, $b:expr) => {{
@@ -29,10 +27,10 @@ fn instant_monotonic() {
#[test]
#[cfg(not(target_arch = "wasm32"))]
-fn instant_monotonic_concurrent() -> crate::thread::Result<()> {
+fn instant_monotonic_concurrent() -> std::thread::Result<()> {
let threads: Vec<_> = (0..8)
.map(|_| {
- crate::thread::spawn(|| {
+ std::thread::spawn(|| {
let mut old = Instant::now();
let count = if cfg!(miri) { 1_000 } else { 5_000_000 };
for _ in 0..count {
@@ -229,46 +227,3 @@ fn big_math() {
check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub);
check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub);
}
-
-macro_rules! bench_instant_threaded {
- ($bench_name:ident, $thread_count:expr) => {
- #[bench]
- #[cfg(not(target_arch = "wasm32"))]
- fn $bench_name(b: &mut Bencher) -> crate::thread::Result<()> {
- use crate::sync::Arc;
- use crate::sync::atomic::{AtomicBool, Ordering};
-
- let running = Arc::new(AtomicBool::new(true));
-
- let threads: Vec<_> = (0..$thread_count)
- .map(|_| {
- let flag = Arc::clone(&running);
- crate::thread::spawn(move || {
- while flag.load(Ordering::Relaxed) {
- black_box(Instant::now());
- }
- })
- })
- .collect();
-
- b.iter(|| {
- let a = Instant::now();
- let b = Instant::now();
- assert!(b >= a);
- });
-
- running.store(false, Ordering::Relaxed);
-
- for t in threads {
- t.join()?;
- }
- Ok(())
- }
- };
-}
-
-bench_instant_threaded!(instant_contention_01_threads, 0);
-bench_instant_threaded!(instant_contention_02_threads, 1);
-bench_instant_threaded!(instant_contention_04_threads, 3);
-bench_instant_threaded!(instant_contention_08_threads, 7);
-bench_instant_threaded!(instant_contention_16_threads, 15);
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index 5fcf7eda8df79..441674936c666 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -11,12 +11,12 @@ use std::str::FromStr;
use std::{env, process};
use bootstrap::{
- Build, CONFIG_CHANGE_HISTORY, Config, Flags, Subcommand, find_recent_config_change_ids,
+ Build, CONFIG_CHANGE_HISTORY, Config, Flags, Subcommand, debug, find_recent_config_change_ids,
human_readable_changes, t,
};
use build_helper::ci::CiEnv;
#[cfg(feature = "tracing")]
-use tracing::{debug, instrument};
+use tracing::instrument;
#[cfg_attr(feature = "tracing", instrument(level = "trace", name = "main"))]
fn main() {
@@ -29,10 +29,8 @@ fn main() {
return;
}
- #[cfg(feature = "tracing")]
debug!("parsing flags");
let flags = Flags::parse(&args);
- #[cfg(feature = "tracing")]
debug!("parsing config based on flags");
let config = Config::parse(flags);
@@ -95,7 +93,6 @@ fn main() {
let dump_bootstrap_shims = config.dump_bootstrap_shims;
let out_dir = config.out.clone();
- #[cfg(feature = "tracing")]
debug!("creating new build based on config");
Build::new(config).build();
@@ -207,8 +204,9 @@ fn check_version(config: &Config) -> Option {
// Due to the conditional compilation via the `tracing` cargo feature, this means that `tracing`
// usages in bootstrap need to be also gated behind the `tracing` feature:
//
-// - `tracing` macros (like `trace!`) and anything from `tracing`, `tracing_subscriber` and
-// `tracing-tree` will need to be gated by `#[cfg(feature = "tracing")]`.
+// - `tracing` macros with log levels (`trace!`, `debug!`, `warn!`, `info`, `error`) should not be
+// used *directly*. You should use the wrapped `tracing` macros which gate the actual invocations
+// behind `feature = "tracing"`.
// - `tracing`'s `#[instrument(..)]` macro will need to be gated like `#![cfg_attr(feature =
// "tracing", instrument(..))]`.
#[cfg(feature = "tracing")]
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index f447d186a5242..cd3558ac6a49b 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -339,7 +339,7 @@ fn copy_self_contained_objects(
// to using gcc from a glibc-targeting toolchain for linking.
// To do that we have to distribute musl startup objects as a part of Rust toolchain
// and link with them manually in the self-contained mode.
- if target.contains("musl") && !target.contains("unikraft") {
+ if target.needs_crt_begin_end() {
let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {
panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)
});
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 3cf25373b8963..82779dc630634 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -1295,7 +1295,9 @@ impl Step for CrtBeginEnd {
}
fn make_run(run: RunConfig<'_>) {
- run.builder.ensure(CrtBeginEnd { target: run.target });
+ if run.target.needs_crt_begin_end() {
+ run.builder.ensure(CrtBeginEnd { target: run.target });
+ }
}
/// Build crtbegin.o/crtend.o for musl target.
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 98490118f7d62..eb1c15b84f3a1 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -575,6 +575,10 @@ impl TargetSelection {
env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin"))
}
+ pub fn needs_crt_begin_end(&self) -> bool {
+ self.contains("musl") && !self.contains("unikraft")
+ }
+
/// Path to the file defining the custom target, if any.
pub fn filepath(&self) -> Option<&Path> {
self.file.as_ref().map(Path::new)
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index d56f35f866cb8..2dd83d5938e9d 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -28,8 +28,6 @@ use std::{env, fs, io, str};
use build_helper::ci::gha;
use build_helper::exit;
use termcolor::{ColorChoice, StandardStream, WriteColor};
-#[cfg(feature = "tracing")]
-use tracing::{debug, instrument, span, trace};
use utils::build_stamp::BuildStamp;
use utils::channel::GitInfo;
@@ -46,6 +44,8 @@ pub use core::builder::PathSet;
pub use core::config::Config;
pub use core::config::flags::{Flags, Subcommand};
+#[cfg(feature = "tracing")]
+use tracing::{instrument, span};
pub use utils::change_tracker::{
CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes,
};
@@ -541,72 +541,71 @@ impl Build {
/// Executes the entire build, as configured by the flags and configuration.
#[cfg_attr(feature = "tracing", instrument(level = "debug", name = "Build::build", skip_all))]
pub fn build(&mut self) {
- #[cfg(feature = "tracing")]
trace!("setting up job management");
unsafe {
crate::utils::job::setup(self);
}
- #[cfg(feature = "tracing")]
- trace!("downloading rustfmt early");
-
// Download rustfmt early so that it can be used in rust-analyzer configs.
+ trace!("downloading rustfmt early");
let _ = &builder::Builder::new(self).initial_rustfmt();
- #[cfg(feature = "tracing")]
- let hardcoded_span =
- span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Suggest, Perf)")
- .entered();
-
- // hardcoded subcommands
- match &self.config.cmd {
- Subcommand::Format { check, all } => {
- return core::build_steps::format::format(
- &builder::Builder::new(self),
- *check,
- *all,
- &self.config.paths,
- );
- }
- Subcommand::Suggest { run } => {
- return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run);
- }
- Subcommand::Perf { .. } => {
- return core::build_steps::perf::perf(&builder::Builder::new(self));
- }
- _cmd => {
- #[cfg(feature = "tracing")]
- debug!(cmd = ?_cmd, "not a hardcoded subcommand; returning to normal handling");
+ // Handle hard-coded subcommands.
+ {
+ #[cfg(feature = "tracing")]
+ let _hardcoded_span = span!(
+ tracing::Level::DEBUG,
+ "handling hardcoded subcommands (Format, Suggest, Perf)"
+ )
+ .entered();
+
+ match &self.config.cmd {
+ Subcommand::Format { check, all } => {
+ return core::build_steps::format::format(
+ &builder::Builder::new(self),
+ *check,
+ *all,
+ &self.config.paths,
+ );
+ }
+ Subcommand::Suggest { run } => {
+ return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run);
+ }
+ Subcommand::Perf { .. } => {
+ return core::build_steps::perf::perf(&builder::Builder::new(self));
+ }
+ _cmd => {
+ debug!(cmd = ?_cmd, "not a hardcoded subcommand; returning to normal handling");
+ }
}
- }
- #[cfg(feature = "tracing")]
- drop(hardcoded_span);
- #[cfg(feature = "tracing")]
- debug!("handling subcommand normally");
+ debug!("handling subcommand normally");
+ }
if !self.config.dry_run() {
#[cfg(feature = "tracing")]
let _real_run_span = span!(tracing::Level::DEBUG, "executing real run").entered();
+ // We first do a dry-run. This is a sanity-check to ensure that
+ // steps don't do anything expensive in the dry-run.
{
#[cfg(feature = "tracing")]
let _sanity_check_span =
span!(tracing::Level::DEBUG, "(1) executing dry-run sanity-check").entered();
-
- // We first do a dry-run. This is a sanity-check to ensure that
- // steps don't do anything expensive in the dry-run.
self.config.dry_run = DryRun::SelfCheck;
let builder = builder::Builder::new(self);
builder.execute_cli();
}
- #[cfg(feature = "tracing")]
- let _actual_run_span =
- span!(tracing::Level::DEBUG, "(2) executing actual run").entered();
- self.config.dry_run = DryRun::Disabled;
- let builder = builder::Builder::new(self);
- builder.execute_cli();
+ // Actual run.
+ {
+ #[cfg(feature = "tracing")]
+ let _actual_run_span =
+ span!(tracing::Level::DEBUG, "(2) executing actual run").entered();
+ self.config.dry_run = DryRun::Disabled;
+ let builder = builder::Builder::new(self);
+ builder.execute_cli();
+ }
} else {
#[cfg(feature = "tracing")]
let _dry_run_span = span!(tracing::Level::DEBUG, "executing dry run").entered();
diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs
index ea56932b40437..caef8ce3088a7 100644
--- a/src/bootstrap/src/utils/mod.rs
+++ b/src/bootstrap/src/utils/mod.rs
@@ -14,6 +14,8 @@ pub(crate) mod render_tests;
pub(crate) mod shared_helpers;
pub(crate) mod tarball;
+pub(crate) mod tracing;
+
#[cfg(feature = "build-metrics")]
pub(crate) mod metrics;
diff --git a/src/bootstrap/src/utils/tracing.rs b/src/bootstrap/src/utils/tracing.rs
new file mode 100644
index 0000000000000..9cd3b6165be61
--- /dev/null
+++ b/src/bootstrap/src/utils/tracing.rs
@@ -0,0 +1,49 @@
+//! Wrapper macros for [`tracing`] macros to avoid having to write `cfg(feature = "tracing")`-gated
+//! `debug!`/`trace!` everytime, e.g.
+//!
+//! ```rust,ignore (example)
+//! #[cfg(feature = "tracing")]
+//! trace!("...");
+//! ```
+//!
+//! When `feature = "tracing"` is inactive, these macros expand to nothing.
+
+#[macro_export]
+macro_rules! trace {
+ ($($tokens:tt)*) => {
+ #[cfg(feature = "tracing")]
+ ::tracing::trace!($($tokens)*)
+ }
+}
+
+#[macro_export]
+macro_rules! debug {
+ ($($tokens:tt)*) => {
+ #[cfg(feature = "tracing")]
+ ::tracing::debug!($($tokens)*)
+ }
+}
+
+#[macro_export]
+macro_rules! warn {
+ ($($tokens:tt)*) => {
+ #[cfg(feature = "tracing")]
+ ::tracing::warn!($($tokens)*)
+ }
+}
+
+#[macro_export]
+macro_rules! info {
+ ($($tokens:tt)*) => {
+ #[cfg(feature = "tracing")]
+ ::tracing::info!($($tokens)*)
+ }
+}
+
+#[macro_export]
+macro_rules! error {
+ ($($tokens:tt)*) => {
+ #[cfg(feature = "tracing")]
+ ::tracing::error!($($tokens)*)
+ }
+}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7853e311a040c..f13428fc4203c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1934,7 +1934,7 @@ fn can_elide_trait_object_lifetime_bound<'tcx>(
preds: &'tcx ty::List>,
tcx: TyCtxt<'tcx>,
) -> bool {
- // Below we quote extracts from https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes
+ // Below we quote extracts from https://doc.rust-lang.org/stable/reference/lifetime-elision.html#default-trait-object-lifetimes
// > If the trait object is used as a type argument of a generic type then the containing type is
// > first used to try to infer a bound.
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 0b4fd9c22589c..f1921b90cc686 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -588,9 +588,9 @@ pub(crate) fn attrs_have_doc_flag<'a>(
/// so that the channel is consistent.
///
/// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
-pub(crate) const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
-pub(crate) static DOC_CHANNEL: Lazy<&'static str> =
- Lazy::new(|| DOC_RUST_LANG_ORG_CHANNEL.rsplit('/').find(|c| !c.is_empty()).unwrap());
+pub(crate) const DOC_RUST_LANG_ORG_VERSION: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
+pub(crate) static RUSTDOC_VERSION: Lazy<&'static str> =
+ Lazy::new(|| DOC_RUST_LANG_ORG_VERSION.rsplit('/').find(|c| !c.is_empty()).unwrap());
/// Render a sequence of macro arms in a format suitable for displaying to the user
/// as part of an item declaration.
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index a072b1256f479..6af35157a43df 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -387,7 +387,7 @@ pub(crate) fn run_global_ctxt(
let help = format!(
"The following guide may be of use:\n\
{}/rustdoc/how-to-write-documentation.html",
- crate::DOC_RUST_LANG_ORG_CHANNEL
+ crate::DOC_RUST_LANG_ORG_VERSION
);
tcx.node_lint(
crate::lint::MISSING_CRATE_LEVEL_DOCS,
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index b4bc0b80d6c66..d957cf1b569e3 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -112,7 +112,7 @@ pub(crate) fn render(
display_krate_with_trailing_slash,
display_krate_version_number,
display_krate_version_extra,
- rust_channel: *crate::clean::utils::DOC_CHANNEL,
+ rust_channel: *crate::clean::utils::RUSTDOC_VERSION,
rustdoc_version,
}
.render()
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 5d96dbc0ee659..1cefdf96bbcd2 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -32,7 +32,7 @@ use crate::html::render::write_shared::write_shared;
use crate::html::url_parts_builder::UrlPartsBuilder;
use crate::html::{layout, sources, static_files};
use crate::scrape_examples::AllCallLocations;
-use crate::try_err;
+use crate::{DOC_RUST_LANG_ORG_VERSION, try_err};
/// Major driving force in all rustdoc rendering. This contains information
/// about where in the tree-like hierarchy rendering is occurring and controls
@@ -730,7 +730,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
\
\
You need to enable JavaScript to use keyboard commands or search.
\
- For more information, browse the rustdoc handbook .
\
+ For more information, browse the rustdoc handbook .
\
\
",
)
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a27a9d202eb80..f7dcb87e4f3d0 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -79,7 +79,7 @@ use crate::html::markdown::{
use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
use crate::html::{highlight, sources};
use crate::scrape_examples::{CallData, CallLocation};
-use crate::{DOC_RUST_LANG_ORG_CHANNEL, try_none};
+use crate::{DOC_RUST_LANG_ORG_VERSION, try_none};
pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
fmt::from_fn(move |f| {
@@ -480,7 +480,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
content.push_str(&format!(
"## More information\n\n\
If you want more information about this feature, please read the [corresponding chapter in \
- the Rustdoc book]({DOC_RUST_LANG_ORG_CHANNEL}/rustdoc/scraped-examples.html)."
+ the Rustdoc book]({DOC_RUST_LANG_ORG_VERSION}/rustdoc/scraped-examples.html)."
));
let mut ids = IdMap::default();
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 37fea09ace310..c50adf116160a 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -924,7 +924,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
dyn compatible .
\
In older versions of Rust, dyn compatibility was called \"object safety\", \
so this trait is not object safe.
",
- base = crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL
+ base = crate::clean::utils::DOC_RUST_LANG_ORG_VERSION
),
);
}
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index ccf4002bb300d..bfd5cb7764fd4 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1534,10 +1534,10 @@ function preLoadCss(cssUrl) {
function buildHelpMenu() {
const book_info = document.createElement("span");
- const channel = getVar("channel");
+ const drloChannel = `https://doc.rust-lang.org/${getVar("channel")}`;
book_info.className = "top";
book_info.innerHTML = `You can find more information in \
-the rustdoc book .`;
+the rustdoc book .`;
const shortcuts = [
["?", "Show this help dialog"],
@@ -1557,8 +1557,8 @@ function preLoadCss(cssUrl) {
div_shortcuts.innerHTML = "Keyboard Shortcuts " + shortcuts + " ";
const infos = [
- `For a full list of all search features, take a look here .`,
+ `For a full list of all search features, take a look \
+ here .`,
"Prefix searches with a type followed by a colon (e.g., fn:
) to \
restrict the search to a given item kind.",
"Accepted kinds are: fn
, mod
, struct
, \
@@ -1568,10 +1568,10 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
-> vec
or String, enum:Cow -> bool
)",
"You can look for items with an exact name by putting double quotes around \
your request: \"string\"
",
- "Look for functions that accept or return \
- slices and \
- arrays by writing \
- square brackets (e.g., -> [u8]
or [] -> Option
)",
+ `Look for functions that accept or return \
+ slices and \
+ arrays by writing square \
+ brackets (e.g., -> [u8]
or [] -> Option
)`,
"Look for items inside another one by searching for a path: vec::Vec
",
].map(x => "" + x + "
").join("");
const div_infos = document.createElement("div");
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 1ad32721e0687..662e951069973 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1,5 +1,5 @@
// ignore-tidy-filelength
-/* global addClass, getNakedUrl, getSettingValue */
+/* global addClass, getNakedUrl, getSettingValue, getVar */
/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
"use strict";
@@ -4923,17 +4923,18 @@ ${item.displayPath}${name} \
}
});
} else if (query.error === null) {
+ const dlroChannel = `https://doc.rust-lang.org/${getVar("channel")}`;
output.className = "search-failed" + extraClass;
output.innerHTML = "No results :( " +
"Try on DuckDuckGo ? " +
"Or try looking in one of these:";
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 9c62826ccc2e3..0034552bdd3b7 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -10,7 +10,7 @@