Auto merge of #150463 - JonathanBrouwer:rollup-ietend4, r=JonathanBrouwer
Rollup of 5 pull requests Successful merges: - rust-lang/rust#147499 (Implement round-ties-to-even for Duration Debug for consistency with f64) - rust-lang/rust#149447 (Rewrite `String::replace_range`) - rust-lang/rust#149469 (Leverage &mut in OnceLock when possible) - rust-lang/rust#149921 (Add new source component that includes GPL-licensed source) - rust-lang/rust#150460 (fix ManuallyDrop::into_inner aliasing (Miri) issues) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
21cf7fb3ff
10 changed files with 254 additions and 183 deletions
|
|
@ -50,8 +50,6 @@ use core::iter::from_fn;
|
|||
use core::ops::Add;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::ops::AddAssign;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use core::ops::{self, Range, RangeBounds};
|
||||
use core::str::pattern::{Pattern, Utf8Pattern};
|
||||
use core::{fmt, hash, ptr, slice};
|
||||
|
|
@ -2059,30 +2057,19 @@ impl String {
|
|||
where
|
||||
R: RangeBounds<usize>,
|
||||
{
|
||||
// Memory safety
|
||||
//
|
||||
// Replace_range does not have the memory safety issues of a vector Splice.
|
||||
// of the vector version. The data is just plain bytes.
|
||||
// We avoid #81138 (nondeterministic RangeBounds impls) because we only use `range` once, here.
|
||||
let checked_range = slice::range(range, ..self.len());
|
||||
|
||||
// WARNING: Inlining this variable would be unsound (#81138)
|
||||
let start = range.start_bound();
|
||||
match start {
|
||||
Included(&n) => assert!(self.is_char_boundary(n)),
|
||||
Excluded(&n) => assert!(self.is_char_boundary(n + 1)),
|
||||
Unbounded => {}
|
||||
};
|
||||
// WARNING: Inlining this variable would be unsound (#81138)
|
||||
let end = range.end_bound();
|
||||
match end {
|
||||
Included(&n) => assert!(self.is_char_boundary(n + 1)),
|
||||
Excluded(&n) => assert!(self.is_char_boundary(n)),
|
||||
Unbounded => {}
|
||||
};
|
||||
assert!(
|
||||
self.is_char_boundary(checked_range.start),
|
||||
"start of range should be a character boundary"
|
||||
);
|
||||
assert!(
|
||||
self.is_char_boundary(checked_range.end),
|
||||
"end of range should be a character boundary"
|
||||
);
|
||||
|
||||
// Using `range` again would be unsound (#81138)
|
||||
// We assume the bounds reported by `range` remain the same, but
|
||||
// an adversarial implementation could change between calls
|
||||
unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes());
|
||||
unsafe { self.as_mut_vec() }.splice(checked_range, replace_with.bytes());
|
||||
}
|
||||
|
||||
/// Replaces the leftmost occurrence of a pattern with another string, in-place.
|
||||
|
|
|
|||
|
|
@ -616,8 +616,15 @@ fn test_replace_range() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_replace_range_char_boundary() {
|
||||
#[should_panic = "start of range should be a character boundary"]
|
||||
fn test_replace_range_start_char_boundary() {
|
||||
let mut s = "Hello, 世界!".to_owned();
|
||||
s.replace_range(8.., "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = "end of range should be a character boundary"]
|
||||
fn test_replace_range_end_char_boundary() {
|
||||
let mut s = "Hello, 世界!".to_owned();
|
||||
s.replace_range(..8, "");
|
||||
}
|
||||
|
|
@ -632,28 +639,32 @@ fn test_replace_range_inclusive_range() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic = "range end index 6 out of range for slice of length 5"]
|
||||
fn test_replace_range_out_of_bounds() {
|
||||
let mut s = String::from("12345");
|
||||
s.replace_range(5..6, "789");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic = "range end index 5 out of range for slice of length 5"]
|
||||
fn test_replace_range_inclusive_out_of_bounds() {
|
||||
let mut s = String::from("12345");
|
||||
s.replace_range(5..=5, "789");
|
||||
}
|
||||
|
||||
// The overflowed index value is target-dependent,
|
||||
// so we don't check for its exact value in the panic message
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic = "out of range for slice of length 3"]
|
||||
fn test_replace_range_start_overflow() {
|
||||
let mut s = String::from("123");
|
||||
s.replace_range((Excluded(usize::MAX), Included(0)), "");
|
||||
}
|
||||
|
||||
// The overflowed index value is target-dependent,
|
||||
// so we don't check for its exact value in the panic message
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic = "out of range for slice of length 3"]
|
||||
fn test_replace_range_end_overflow() {
|
||||
let mut s = String::from("456");
|
||||
s.replace_range((Included(0), Included(usize::MAX)), "");
|
||||
|
|
|
|||
|
|
@ -200,7 +200,9 @@ impl<T> ManuallyDrop<T> {
|
|||
#[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")]
|
||||
#[inline(always)]
|
||||
pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
|
||||
slot.value.into_inner()
|
||||
// Cannot use `MaybeDangling::into_inner` as that does not yet have the desired semantics.
|
||||
// SAFETY: We know this is a valid `T`. `slot` will not be dropped.
|
||||
unsafe { (&raw const slot).cast::<T>().read() }
|
||||
}
|
||||
|
||||
/// Takes the value from the `ManuallyDrop<T>` container out.
|
||||
|
|
|
|||
|
|
@ -1315,39 +1315,54 @@ impl fmt::Debug for Duration {
|
|||
// need to perform rounding to match the semantics of printing
|
||||
// normal floating point numbers. However, we only need to do work
|
||||
// when rounding up. This happens if the first digit of the
|
||||
// remaining ones is >= 5.
|
||||
// remaining ones is >= 5. When the first digit is exactly 5, rounding
|
||||
// follows IEEE-754 round-ties-to-even semantics: we only round up
|
||||
// if the last written digit is odd.
|
||||
let integer_part = if fractional_part > 0 && fractional_part >= divisor * 5 {
|
||||
// Round up the number contained in the buffer. We go through
|
||||
// the buffer backwards and keep track of the carry.
|
||||
let mut rev_pos = pos;
|
||||
let mut carry = true;
|
||||
while carry && rev_pos > 0 {
|
||||
rev_pos -= 1;
|
||||
|
||||
// If the digit in the buffer is not '9', we just need to
|
||||
// increment it and can stop then (since we don't have a
|
||||
// carry anymore). Otherwise, we set it to '0' (overflow)
|
||||
// and continue.
|
||||
if buf[rev_pos] < b'9' {
|
||||
buf[rev_pos] += 1;
|
||||
carry = false;
|
||||
} else {
|
||||
buf[rev_pos] = b'0';
|
||||
}
|
||||
}
|
||||
|
||||
// If we still have the carry bit set, that means that we set
|
||||
// the whole buffer to '0's and need to increment the integer
|
||||
// part.
|
||||
if carry {
|
||||
// If `integer_part == u64::MAX` and precision < 9, any
|
||||
// carry of the overflow during rounding of the
|
||||
// `fractional_part` into the `integer_part` will cause the
|
||||
// `integer_part` itself to overflow. Avoid this by using an
|
||||
// `Option<u64>`, with `None` representing `u64::MAX + 1`.
|
||||
integer_part.checked_add(1)
|
||||
// For ties (fractional_part == divisor * 5), only round up if last digit is odd
|
||||
let is_tie = fractional_part == divisor * 5;
|
||||
let last_digit_is_odd = if pos > 0 {
|
||||
(buf[pos - 1] - b'0') % 2 == 1
|
||||
} else {
|
||||
// No fractional digits - check the integer part
|
||||
(integer_part % 2) == 1
|
||||
};
|
||||
|
||||
if is_tie && !last_digit_is_odd {
|
||||
Some(integer_part)
|
||||
} else {
|
||||
// Round up the number contained in the buffer. We go through
|
||||
// the buffer backwards and keep track of the carry.
|
||||
let mut rev_pos = pos;
|
||||
let mut carry = true;
|
||||
while carry && rev_pos > 0 {
|
||||
rev_pos -= 1;
|
||||
|
||||
// If the digit in the buffer is not '9', we just need to
|
||||
// increment it and can stop then (since we don't have a
|
||||
// carry anymore). Otherwise, we set it to '0' (overflow)
|
||||
// and continue.
|
||||
if buf[rev_pos] < b'9' {
|
||||
buf[rev_pos] += 1;
|
||||
carry = false;
|
||||
} else {
|
||||
buf[rev_pos] = b'0';
|
||||
}
|
||||
}
|
||||
|
||||
// If we still have the carry bit set, that means that we set
|
||||
// the whole buffer to '0's and need to increment the integer
|
||||
// part.
|
||||
if carry {
|
||||
// If `integer_part == u64::MAX` and precision < 9, any
|
||||
// carry of the overflow during rounding of the
|
||||
// `fractional_part` into the `integer_part` will cause the
|
||||
// `integer_part` itself to overflow. Avoid this by using an
|
||||
// `Option<u64>`, with `None` representing `u64::MAX + 1`.
|
||||
integer_part.checked_add(1)
|
||||
} else {
|
||||
Some(integer_part)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Some(integer_part)
|
||||
|
|
|
|||
|
|
@ -439,7 +439,6 @@ fn debug_formatting_precision_two() {
|
|||
assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s");
|
||||
assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s");
|
||||
assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s");
|
||||
assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s");
|
||||
assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s");
|
||||
}
|
||||
|
||||
|
|
@ -480,6 +479,15 @@ fn debug_formatting_precision_high() {
|
|||
assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug_formatting_round_to_even() {
|
||||
assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s");
|
||||
assert_eq!(format!("{:.0?}", Duration::new(2, 500_000_000)), "2s");
|
||||
assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms");
|
||||
assert_eq!(format!("{:.0?}", Duration::new(0, 2_500_000)), "2ms");
|
||||
assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.10s");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_const() {
|
||||
// test that the methods of `Duration` are usable in a const context
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use super::once::OnceExclusiveState;
|
||||
use crate::cell::UnsafeCell;
|
||||
use crate::fmt;
|
||||
use crate::marker::PhantomData;
|
||||
|
|
@ -152,8 +153,8 @@ impl<T> OnceLock<T> {
|
|||
#[stable(feature = "once_cell", since = "1.70.0")]
|
||||
#[rustc_should_not_be_called_on_const_items]
|
||||
pub fn get(&self) -> Option<&T> {
|
||||
if self.is_initialized() {
|
||||
// Safe b/c checked is_initialized
|
||||
if self.initialized() {
|
||||
// Safe b/c checked initialized
|
||||
Some(unsafe { self.get_unchecked() })
|
||||
} else {
|
||||
None
|
||||
|
|
@ -170,8 +171,8 @@ impl<T> OnceLock<T> {
|
|||
#[inline]
|
||||
#[stable(feature = "once_cell", since = "1.70.0")]
|
||||
pub fn get_mut(&mut self) -> Option<&mut T> {
|
||||
if self.is_initialized() {
|
||||
// Safe b/c checked is_initialized and we have a unique access
|
||||
if self.initialized_mut() {
|
||||
// Safe b/c checked initialized and we have a unique access
|
||||
Some(unsafe { self.get_unchecked_mut() })
|
||||
} else {
|
||||
None
|
||||
|
|
@ -402,14 +403,12 @@ impl<T> OnceLock<T> {
|
|||
// NOTE: We need to perform an acquire on the state in this method
|
||||
// in order to correctly synchronize `LazyLock::force`. This is
|
||||
// currently done by calling `self.get()`, which in turn calls
|
||||
// `self.is_initialized()`, which in turn performs the acquire.
|
||||
// `self.initialized()`, which in turn performs the acquire.
|
||||
if let Some(value) = self.get() {
|
||||
return Ok(value);
|
||||
}
|
||||
self.initialize(f)?;
|
||||
|
||||
debug_assert!(self.is_initialized());
|
||||
|
||||
// SAFETY: The inner value has been initialized
|
||||
Ok(unsafe { self.get_unchecked() })
|
||||
}
|
||||
|
|
@ -451,10 +450,10 @@ impl<T> OnceLock<T> {
|
|||
where
|
||||
F: FnOnce() -> Result<T, E>,
|
||||
{
|
||||
if self.get().is_none() {
|
||||
if self.get_mut().is_none() {
|
||||
self.initialize(f)?;
|
||||
}
|
||||
debug_assert!(self.is_initialized());
|
||||
|
||||
// SAFETY: The inner value has been initialized
|
||||
Ok(unsafe { self.get_unchecked_mut() })
|
||||
}
|
||||
|
|
@ -503,22 +502,32 @@ impl<T> OnceLock<T> {
|
|||
#[inline]
|
||||
#[stable(feature = "once_cell", since = "1.70.0")]
|
||||
pub fn take(&mut self) -> Option<T> {
|
||||
if self.is_initialized() {
|
||||
if self.initialized_mut() {
|
||||
self.once = Once::new();
|
||||
// SAFETY: `self.value` is initialized and contains a valid `T`.
|
||||
// `self.once` is reset, so `is_initialized()` will be false again
|
||||
// `self.once` is reset, so `initialized()` will be false again
|
||||
// which prevents the value from being read twice.
|
||||
unsafe { Some((&mut *self.value.get()).assume_init_read()) }
|
||||
unsafe { Some(self.value.get_mut().assume_init_read()) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_initialized(&self) -> bool {
|
||||
fn initialized(&self) -> bool {
|
||||
self.once.is_completed()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn initialized_mut(&mut self) -> bool {
|
||||
// `state()` does not perform an atomic load, so prefer it over `is_complete()`.
|
||||
let state = self.once.state();
|
||||
match state {
|
||||
OnceExclusiveState::Complete => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[optimize(size)]
|
||||
fn initialize<F, E>(&self, f: F) -> Result<(), E>
|
||||
|
|
@ -552,7 +561,7 @@ impl<T> OnceLock<T> {
|
|||
/// The cell must be initialized
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(&self) -> &T {
|
||||
debug_assert!(self.is_initialized());
|
||||
debug_assert!(self.initialized());
|
||||
unsafe { (&*self.value.get()).assume_init_ref() }
|
||||
}
|
||||
|
||||
|
|
@ -561,8 +570,8 @@ impl<T> OnceLock<T> {
|
|||
/// The cell must be initialized
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
|
||||
debug_assert!(self.is_initialized());
|
||||
unsafe { (&mut *self.value.get()).assume_init_mut() }
|
||||
debug_assert!(self.initialized_mut());
|
||||
unsafe { self.value.get_mut().assume_init_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -690,11 +699,11 @@ impl<T: Eq> Eq for OnceLock<T> {}
|
|||
unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if self.is_initialized() {
|
||||
if self.initialized_mut() {
|
||||
// SAFETY: The cell is initialized and being dropped, so it can't
|
||||
// be accessed again. We also don't touch the `T` other than
|
||||
// dropping it, which validates our usage of #[may_dangle].
|
||||
unsafe { (&mut *self.value.get()).assume_init_drop() };
|
||||
unsafe { self.value.get_mut().assume_init_drop() };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1211,6 +1211,9 @@ impl Step for Src {
|
|||
}
|
||||
}
|
||||
|
||||
/// Tarball for people who want to build rustc and other components from the source.
|
||||
/// Does not contain GPL code, which is separated into `PlainSourceTarballGpl`
|
||||
/// for licensing reasons.
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct PlainSourceTarball;
|
||||
|
||||
|
|
@ -1233,51 +1236,18 @@ impl Step for PlainSourceTarball {
|
|||
|
||||
/// Creates the plain source tarball
|
||||
fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
|
||||
// NOTE: This is a strange component in a lot of ways. It uses `src` as the target, which
|
||||
// means neither rustup nor rustup-toolchain-install-master know how to download it.
|
||||
// It also contains symbolic links, unlike other any other dist tarball.
|
||||
// It's used for distros building rustc from source in a pre-vendored environment.
|
||||
let mut tarball = Tarball::new(builder, "rustc", "src");
|
||||
tarball.permit_symlinks(true);
|
||||
let plain_dst_src = tarball.image_dir();
|
||||
|
||||
// This is the set of root paths which will become part of the source package
|
||||
let src_files = [
|
||||
// tidy-alphabetical-start
|
||||
".gitmodules",
|
||||
"CONTRIBUTING.md",
|
||||
"COPYRIGHT",
|
||||
"Cargo.lock",
|
||||
"Cargo.toml",
|
||||
"LICENSE-APACHE",
|
||||
"LICENSE-MIT",
|
||||
"README.md",
|
||||
"RELEASES.md",
|
||||
"REUSE.toml",
|
||||
"bootstrap.example.toml",
|
||||
"configure",
|
||||
"license-metadata.json",
|
||||
"package.json",
|
||||
"x",
|
||||
"x.ps1",
|
||||
"x.py",
|
||||
"yarn.lock",
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
|
||||
|
||||
copy_src_dirs(
|
||||
let tarball = prepare_source_tarball(
|
||||
builder,
|
||||
&builder.src,
|
||||
&src_dirs,
|
||||
"src",
|
||||
&[
|
||||
// We don't currently use the GCC source code for building any official components,
|
||||
// it is very big, and has unclear licensing implications due to being GPL licensed.
|
||||
// We thus exclude it from the source tarball from now.
|
||||
"src/gcc",
|
||||
],
|
||||
plain_dst_src,
|
||||
);
|
||||
|
||||
let plain_dst_src = tarball.image_dir();
|
||||
// We keep something in src/gcc because it is a registered submodule,
|
||||
// and if it misses completely it can cause issues elsewhere
|
||||
// (see https://github.com/rust-lang/rust/issues/137332).
|
||||
|
|
@ -1289,76 +1259,138 @@ impl Step for PlainSourceTarball {
|
|||
"The GCC source code is not included due to unclear licensing implications\n"
|
||||
));
|
||||
}
|
||||
|
||||
// Copy the files normally
|
||||
for item in &src_files {
|
||||
builder.copy_link(
|
||||
&builder.src.join(item),
|
||||
&plain_dst_src.join(item),
|
||||
FileType::Regular,
|
||||
);
|
||||
}
|
||||
|
||||
// Create the version file
|
||||
builder.create(&plain_dst_src.join("version"), &builder.rust_version());
|
||||
|
||||
// Create the files containing git info, to ensure --version outputs the same.
|
||||
let write_git_info = |info: Option<&Info>, path: &Path| {
|
||||
if let Some(info) = info {
|
||||
t!(std::fs::create_dir_all(path));
|
||||
channel::write_commit_hash_file(path, &info.sha);
|
||||
channel::write_commit_info_file(path, info);
|
||||
}
|
||||
};
|
||||
write_git_info(builder.rust_info().info(), plain_dst_src);
|
||||
write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo"));
|
||||
|
||||
if builder.config.dist_vendor {
|
||||
builder.require_and_update_all_submodules();
|
||||
|
||||
// Vendor packages that are required by opt-dist to collect PGO profiles.
|
||||
let pkgs_for_pgo_training = build_helper::LLVM_PGO_CRATES
|
||||
.iter()
|
||||
.chain(build_helper::RUSTC_PGO_CRATES)
|
||||
.map(|pkg| {
|
||||
let mut manifest_path =
|
||||
builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks");
|
||||
manifest_path.push(pkg);
|
||||
manifest_path.push("Cargo.toml");
|
||||
manifest_path
|
||||
});
|
||||
|
||||
// Vendor all Cargo dependencies
|
||||
let vendor = builder.ensure(Vendor {
|
||||
sync_args: pkgs_for_pgo_training.collect(),
|
||||
versioned_dirs: true,
|
||||
root_dir: plain_dst_src.into(),
|
||||
output_dir: VENDOR_DIR.into(),
|
||||
});
|
||||
|
||||
let cargo_config_dir = plain_dst_src.join(".cargo");
|
||||
builder.create_dir(&cargo_config_dir);
|
||||
builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
|
||||
}
|
||||
|
||||
// Delete extraneous directories
|
||||
// FIXME: if we're managed by git, we should probably instead ask git if the given path
|
||||
// is managed by it?
|
||||
for entry in walkdir::WalkDir::new(tarball.image_dir())
|
||||
.follow_links(true)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__"))
|
||||
{
|
||||
t!(fs::remove_dir_all(entry.path()));
|
||||
}
|
||||
}
|
||||
|
||||
tarball.bare()
|
||||
}
|
||||
}
|
||||
|
||||
/// Tarball with *all* source code for source builds, including GPL-licensed code.
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct PlainSourceTarballGpl;
|
||||
|
||||
impl Step for PlainSourceTarballGpl {
|
||||
/// Produces the location of the tarball generated
|
||||
type Output = GeneratedTarball;
|
||||
const IS_HOST: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.alias("rustc-src-gpl")
|
||||
}
|
||||
|
||||
fn is_default_step(builder: &Builder<'_>) -> bool {
|
||||
builder.config.rust_dist_src
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(PlainSourceTarballGpl);
|
||||
}
|
||||
|
||||
/// Creates the plain source tarball
|
||||
fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
|
||||
let tarball = prepare_source_tarball(builder, "src-gpl", &[]);
|
||||
tarball.bare()
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_source_tarball<'a>(
|
||||
builder: &'a Builder<'a>,
|
||||
name: &str,
|
||||
exclude_dirs: &[&str],
|
||||
) -> Tarball<'a> {
|
||||
// NOTE: This is a strange component in a lot of ways. It uses `src` as the target, which
|
||||
// means neither rustup nor rustup-toolchain-install-master know how to download it.
|
||||
// It also contains symbolic links, unlike other any other dist tarball.
|
||||
// It's used for distros building rustc from source in a pre-vendored environment.
|
||||
let mut tarball = Tarball::new(builder, "rustc", name);
|
||||
tarball.permit_symlinks(true);
|
||||
let plain_dst_src = tarball.image_dir();
|
||||
|
||||
// This is the set of root paths which will become part of the source package
|
||||
let src_files = [
|
||||
// tidy-alphabetical-start
|
||||
".gitmodules",
|
||||
"CONTRIBUTING.md",
|
||||
"COPYRIGHT",
|
||||
"Cargo.lock",
|
||||
"Cargo.toml",
|
||||
"LICENSE-APACHE",
|
||||
"LICENSE-MIT",
|
||||
"README.md",
|
||||
"RELEASES.md",
|
||||
"REUSE.toml",
|
||||
"bootstrap.example.toml",
|
||||
"configure",
|
||||
"license-metadata.json",
|
||||
"package.json",
|
||||
"x",
|
||||
"x.ps1",
|
||||
"x.py",
|
||||
"yarn.lock",
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
|
||||
|
||||
copy_src_dirs(builder, &builder.src, &src_dirs, exclude_dirs, plain_dst_src);
|
||||
|
||||
// Copy the files normally
|
||||
for item in &src_files {
|
||||
builder.copy_link(&builder.src.join(item), &plain_dst_src.join(item), FileType::Regular);
|
||||
}
|
||||
|
||||
// Create the version file
|
||||
builder.create(&plain_dst_src.join("version"), &builder.rust_version());
|
||||
|
||||
// Create the files containing git info, to ensure --version outputs the same.
|
||||
let write_git_info = |info: Option<&Info>, path: &Path| {
|
||||
if let Some(info) = info {
|
||||
t!(std::fs::create_dir_all(path));
|
||||
channel::write_commit_hash_file(path, &info.sha);
|
||||
channel::write_commit_info_file(path, info);
|
||||
}
|
||||
};
|
||||
write_git_info(builder.rust_info().info(), plain_dst_src);
|
||||
write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo"));
|
||||
|
||||
if builder.config.dist_vendor {
|
||||
builder.require_and_update_all_submodules();
|
||||
|
||||
// Vendor packages that are required by opt-dist to collect PGO profiles.
|
||||
let pkgs_for_pgo_training =
|
||||
build_helper::LLVM_PGO_CRATES.iter().chain(build_helper::RUSTC_PGO_CRATES).map(|pkg| {
|
||||
let mut manifest_path =
|
||||
builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks");
|
||||
manifest_path.push(pkg);
|
||||
manifest_path.push("Cargo.toml");
|
||||
manifest_path
|
||||
});
|
||||
|
||||
// Vendor all Cargo dependencies
|
||||
let vendor = builder.ensure(Vendor {
|
||||
sync_args: pkgs_for_pgo_training.collect(),
|
||||
versioned_dirs: true,
|
||||
root_dir: plain_dst_src.into(),
|
||||
output_dir: VENDOR_DIR.into(),
|
||||
});
|
||||
|
||||
let cargo_config_dir = plain_dst_src.join(".cargo");
|
||||
builder.create_dir(&cargo_config_dir);
|
||||
builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
|
||||
}
|
||||
|
||||
// Delete extraneous directories
|
||||
// FIXME: if we're managed by git, we should probably instead ask git if the given path
|
||||
// is managed by it?
|
||||
for entry in walkdir::WalkDir::new(tarball.image_dir())
|
||||
.follow_links(true)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__")) {
|
||||
t!(fs::remove_dir_all(entry.path()));
|
||||
}
|
||||
}
|
||||
tarball
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Cargo {
|
||||
pub build_compiler: Compiler,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ expression: dist
|
|||
[Dist] dist::PlainSourceTarball
|
||||
targets: [x86_64-unknown-linux-gnu]
|
||||
- Set({dist::rustc-src})
|
||||
[Dist] dist::PlainSourceTarballGpl
|
||||
targets: [x86_64-unknown-linux-gnu]
|
||||
- Set({dist::rustc-src-gpl})
|
||||
[Dist] dist::ReproducibleArtifacts
|
||||
targets: [x86_64-unknown-linux-gnu]
|
||||
- Set({dist::reproducible-artifacts})
|
||||
|
|
|
|||
|
|
@ -986,6 +986,7 @@ impl<'a> Builder<'a> {
|
|||
// and force us to rebuild tools after vendoring dependencies.
|
||||
// To work around this, create the Tarball after building all the tools.
|
||||
dist::PlainSourceTarball,
|
||||
dist::PlainSourceTarballGpl,
|
||||
dist::BuildManifest,
|
||||
dist::ReproducibleArtifacts,
|
||||
dist::Gcc
|
||||
|
|
|
|||
3
src/tools/miri/tests/pass/issues/issue-miri-4793.rs
Normal file
3
src/tools/miri/tests/pass/issues/issue-miri-4793.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
let _ = std::panic::catch_unwind(|| Box::<str>::from("..."));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue