Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 4 pull requests #134677

Merged
merged 11 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,6 @@ declare_features! (
(accepted, const_refs_to_static, "1.83.0", Some(119618)),
/// Allows implementing `Copy` for closures where possible (RFC 2132).
(accepted, copy_closures, "1.26.0", Some(44490)),
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
/// instrumentation of that function.
(accepted, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605)),
/// Allows `crate` in paths.
(accepted, crate_in_paths, "1.30.0", Some(45477)),
/// Allows users to provide classes for fenced code block using `class:classname`.
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
EncodeCrossCrate::No, experimental!(no_sanitize)
),
ungated!(
gated!(
coverage, Normal, template!(OneOf: &[sym::off, sym::on]),
ErrorPreceding, EncodeCrossCrate::No,
coverage_attribute, experimental!(coverage)
),

ungated!(
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@ declare_features! (
(unstable, coroutine_clone, "1.65.0", Some(95360)),
/// Allows defining coroutines.
(unstable, coroutines, "1.21.0", Some(43122)),
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
/// instrumentation of that function.
(unstable, coverage_attribute, "1.74.0", Some(84605)),
/// Allows non-builtin attributes in inner attribute position.
(unstable, custom_inner_attributes, "1.30.0", Some(54726)),
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ pub trait Eq: PartialEq<Self> {
#[rustc_builtin_macro]
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)]
#[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))]
#[allow_internal_unstable(coverage_attribute)]
pub macro Eq($item:item) {
/* compiler built-in */
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@
//
// Library features:
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(coverage_attribute))]
#![cfg_attr(bootstrap, feature(do_not_recommend))]
#![feature(array_ptr_get)]
#![feature(asm_experimental_arch)]
#![feature(const_eval_select)]
#![feature(const_typed_swap)]
#![feature(core_intrinsics)]
#![feature(coverage_attribute)]
#![feature(internal_impls_macro)]
#![feature(ip)]
#![feature(is_ascii_octdigit)]
Expand Down
6 changes: 2 additions & 4 deletions library/core/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1673,8 +1673,7 @@ pub(crate) mod builtin {
///
/// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(test, rustc_attrs)]
#[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))]
#[allow_internal_unstable(test, rustc_attrs, coverage_attribute)]
#[rustc_builtin_macro]
pub macro test($item:item) {
/* compiler built-in */
Expand All @@ -1687,8 +1686,7 @@ pub(crate) mod builtin {
soft,
reason = "`bench` is a part of custom test frameworks which are unstable"
)]
#[allow_internal_unstable(test, rustc_attrs)]
#[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))]
#[allow_internal_unstable(test, rustc_attrs, coverage_attribute)]
#[rustc_builtin_macro]
pub macro bench($item:item) {
/* compiler built-in */
Expand Down
69 changes: 69 additions & 0 deletions src/build_helper/src/fs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//! Misc filesystem related helpers for use by bootstrap and tools.
use std::fs::Metadata;
use std::path::Path;
use std::{fs, io};

#[cfg(test)]
mod tests;

/// Helper to ignore [`std::io::ErrorKind::NotFound`], but still propagate other
/// [`std::io::ErrorKind`]s.
pub fn ignore_not_found<Op>(mut op: Op) -> io::Result<()>
where
Op: FnMut() -> io::Result<()>,
{
match op() {
Ok(()) => Ok(()),
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()),
Err(e) => Err(e),
}
}

/// A wrapper around [`std::fs::remove_dir_all`] that can also be used on *non-directory entries*,
/// including files and symbolic links.
///
/// - This will produce an error if the target path is not found.
/// - Like [`std::fs::remove_dir_all`], this helper does not traverse symbolic links, will remove
/// symbolic link itself.
/// - This helper is **not** robust against races on the underlying filesystem, behavior is
/// unspecified if this helper is called concurrently.
/// - This helper is not robust against TOCTOU problems.
///
/// FIXME: this implementation is insufficiently robust to replace bootstrap's clean `rm_rf`
/// implementation:
///
/// - This implementation currently does not perform retries.
#[track_caller]
pub fn recursive_remove<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref();
let metadata = fs::symlink_metadata(path)?;
#[cfg(windows)]
let is_dir_like = |meta: &fs::Metadata| {
use std::os::windows::fs::FileTypeExt;
meta.is_dir() || meta.file_type().is_symlink_dir()
};
#[cfg(not(windows))]
let is_dir_like = fs::Metadata::is_dir;

if is_dir_like(&metadata) {
fs::remove_dir_all(path)
} else {
try_remove_op_set_perms(fs::remove_file, path, metadata)
}
}

fn try_remove_op_set_perms<'p, Op>(mut op: Op, path: &'p Path, metadata: Metadata) -> io::Result<()>
where
Op: FnMut(&'p Path) -> io::Result<()>,
{
match op(path) {
Ok(()) => Ok(()),
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {
let mut perms = metadata.permissions();
perms.set_readonly(false);
fs::set_permissions(path, perms)?;
op(path)
}
Err(e) => Err(e),
}
}
214 changes: 214 additions & 0 deletions src/build_helper/src/fs/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#![deny(unused_must_use)]

use std::{env, fs, io};

use super::recursive_remove;

mod recursive_remove_tests {
use super::*;

// Basic cases

#[test]
fn nonexistent_path() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_nonexistent_path");
assert!(fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound));
assert!(recursive_remove(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound));
}

#[test]
fn file() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_file");
fs::write(&path, b"").unwrap();
assert!(fs::symlink_metadata(&path).is_ok());
assert!(recursive_remove(&path).is_ok());
assert!(fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound));
}

mod dir_tests {
use super::*;

#[test]
fn dir_empty() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_dir_tests_dir_empty");
fs::create_dir_all(&path).unwrap();
assert!(fs::symlink_metadata(&path).is_ok());
assert!(recursive_remove(&path).is_ok());
assert!(
fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
}

#[test]
fn dir_recursive() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_dir_tests_dir_recursive");
fs::create_dir_all(&path).unwrap();
assert!(fs::symlink_metadata(&path).is_ok());

let file_a = path.join("a.txt");
fs::write(&file_a, b"").unwrap();
assert!(fs::symlink_metadata(&file_a).is_ok());

let dir_b = path.join("b");
fs::create_dir_all(&dir_b).unwrap();
assert!(fs::symlink_metadata(&dir_b).is_ok());

let file_c = dir_b.join("c.rs");
fs::write(&file_c, b"").unwrap();
assert!(fs::symlink_metadata(&file_c).is_ok());

assert!(recursive_remove(&path).is_ok());

assert!(
fs::symlink_metadata(&file_a).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
assert!(
fs::symlink_metadata(&dir_b).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
assert!(
fs::symlink_metadata(&file_c).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
}
}

/// Check that [`recursive_remove`] does not traverse symlinks and only removes symlinks
/// themselves.
///
/// Symlink-to-file versus symlink-to-dir is a distinction that's important on Windows, but not
/// on Unix.
mod symlink_tests {
use super::*;

#[cfg(unix)]
#[test]
fn unix_symlink() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_unix_symlink");
let symlink_path =
tmpdir.join("__INTERNAL_BOOTSTRAP__symlink_tests_unix_symlink_symlink");
fs::write(&path, b"").unwrap();

assert!(fs::symlink_metadata(&path).is_ok());
assert!(
fs::symlink_metadata(&symlink_path)
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);

std::os::unix::fs::symlink(&path, &symlink_path).unwrap();

assert!(recursive_remove(&symlink_path).is_ok());

// Check that the symlink got removed...
assert!(
fs::symlink_metadata(&symlink_path)
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
// ... but pointed-to file still exists.
assert!(fs::symlink_metadata(&path).is_ok());

fs::remove_file(&path).unwrap();
}

#[cfg(windows)]
#[test]
fn windows_symlink_to_file() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_windows_symlink_to_file");
let symlink_path = tmpdir
.join("__INTERNAL_BOOTSTRAP_SYMLINK_symlink_tests_windows_symlink_to_file_symlink");
fs::write(&path, b"").unwrap();

assert!(fs::symlink_metadata(&path).is_ok());
assert!(
fs::symlink_metadata(&symlink_path)
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);

std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();

assert!(recursive_remove(&symlink_path).is_ok());

// Check that the symlink-to-file got removed...
assert!(
fs::symlink_metadata(&symlink_path)
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
// ... but pointed-to file still exists.
assert!(fs::symlink_metadata(&path).is_ok());

fs::remove_file(&path).unwrap();
}

#[cfg(windows)]
#[test]
fn windows_symlink_to_dir() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_windows_symlink_to_dir");
let symlink_path =
tmpdir.join("__INTERNAL_BOOTSTRAP_symlink_tests_windows_symlink_to_dir_symlink");
fs::create_dir_all(&path).unwrap();

assert!(fs::symlink_metadata(&path).is_ok());
assert!(
fs::symlink_metadata(&symlink_path)
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);

std::os::windows::fs::symlink_dir(&path, &symlink_path).unwrap();

assert!(recursive_remove(&symlink_path).is_ok());

// Check that the symlink-to-dir got removed...
assert!(
fs::symlink_metadata(&symlink_path)
.is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
// ... but pointed-to dir still exists.
assert!(fs::symlink_metadata(&path).is_ok());

fs::remove_dir_all(&path).unwrap();
}
}

/// Read-only file and directories only need special handling on Windows.
#[cfg(windows)]
mod readonly_tests {
use super::*;

#[test]
fn overrides_readonly() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_readonly_tests_overrides_readonly");

// In case of a previous failed test:
if let Ok(mut perms) = fs::symlink_metadata(&path).map(|m| m.permissions()) {
perms.set_readonly(false);
fs::set_permissions(&path, perms).unwrap();
fs::remove_file(&path).unwrap();
}

fs::write(&path, b"").unwrap();

let mut perms = fs::symlink_metadata(&path).unwrap().permissions();
perms.set_readonly(true);
fs::set_permissions(&path, perms).unwrap();

// Check that file exists but is read-only, and that normal `std::fs::remove_file` fails
// to delete the file.
assert!(fs::symlink_metadata(&path).is_ok_and(|m| m.permissions().readonly()));
assert!(
fs::remove_file(&path).is_err_and(|e| e.kind() == io::ErrorKind::PermissionDenied)
);

assert!(recursive_remove(&path).is_ok());

assert!(
fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound)
);
}
}
}
1 change: 1 addition & 0 deletions src/build_helper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pub mod ci;
pub mod drop_bomb;
pub mod fs;
pub mod git;
pub mod metrics;
pub mod stage0_parser;
Expand Down
1 change: 1 addition & 0 deletions src/doc/rustc/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
- [\*-nto-qnx-\*](platform-support/nto-qnx.md)
- [*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md)
- [*-unknown-hermit](platform-support/hermit.md)
- [*-unknown-freebsd](platform-support/freebsd.md)
- [\*-unknown-netbsd\*](platform-support/netbsd.md)
- [*-unknown-openbsd](platform-support/openbsd.md)
- [*-unknown-redox](platform-support/redox.md)
Expand Down
Loading
Loading