Skip to content
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
83 changes: 83 additions & 0 deletions library/core/src/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,89 @@ use crate::{fmt, intrinsics, ptr, slice};
/// std::process::exit(*code); // UB! Accessing uninitialized memory.
/// }
/// ```
///
/// # Validity
///
/// `MaybeUninit<T>` has no validity requirements –- any sequence of [bytes] of
/// the appropriate length, initialized or uninitialized, are a valid
/// representation.
///
/// Moving or copying a value of type `MaybeUninit<T>` (i.e., performing a
/// "typed copy") will exactly preserve the contents, including the
/// [provenance], of all non-padding bytes of type `T` in the value's
/// representation.
///
/// Therefore `MaybeUninit` can be used to perform a round trip of a value from
/// type `T` to type `MaybeUninit<U>` then back to type `T`, while preserving
/// the original value, if two conditions are met. One, type `U` must have the
/// same size as type `T`. Two, for all byte offsets where type `U` has padding,
/// the corresponding bytes in the representation of the value must be
/// uninitialized.
///
/// For example, due to the fact that the type `[u8; size_of::<T>]` has no
/// padding, the following is sound for any type `T` and will return the
/// original value:
///
/// ```rust,no_run
/// # use core::mem::{MaybeUninit, transmute};
/// # struct T;
/// fn identity(t: T) -> T {
/// unsafe {
/// let u: MaybeUninit<[u8; size_of::<T>()]> = transmute(t);
/// transmute(u) // OK.
/// }
/// }
/// ```
///
/// Note: Copying a value that contains references may implicitly reborrow them
/// causing the provenance of the returned value to differ from that of the
/// original. This applies equally to the trivial identity function:
///
/// ```rust,no_run
/// fn trivial_identity<T>(t: T) -> T { t }
/// ```
///
/// Note: Moving or copying a value whose representation has initialized bytes
/// at byte offsets where the type has padding may lose the value of those
/// bytes, so while the original value will be preserved, the original
/// *representation* of that value as bytes may not be. Again, this applies
/// equally to `trivial_identity`.
///
/// Note: Performing this round trip when type `U` has padding at byte offsets
/// where the representation of the original value has initialized bytes may
/// produce undefined behavior or a different value. For example, the following
/// is unsound since `T` requires all bytes to be initialized:
///
/// ```rust,no_run
/// # use core::mem::{MaybeUninit, transmute};
/// #[repr(C)] struct T([u8; 4]);
/// #[repr(C)] struct U(u8, u16);
/// fn unsound_identity(t: T) -> T {
/// unsafe {
/// let u: MaybeUninit<U> = transmute(t);
/// transmute(u) // UB.
/// }
/// }
/// ```
///
/// Conversely, the following is sound since `T` allows uninitialized bytes in
/// the representation of a value, but the round trip may alter the value:
///
/// ```rust,no_run
/// # use core::mem::{MaybeUninit, transmute};
/// #[repr(C)] struct T(MaybeUninit<[u8; 4]>);
/// #[repr(C)] struct U(u8, u16);
/// fn non_identity(t: T) -> T {
/// unsafe {
/// // May lose an initialized byte.
/// let u: MaybeUninit<U> = transmute(t);
/// transmute(u)
/// }
/// }
/// ```
///
/// [bytes]: ../../reference/memory-model.html#bytes
/// [provenance]: crate::ptr#provenance
#[stable(feature = "maybe_uninit", since = "1.36.0")]
// Lang item so we can wrap other types in it. This is useful for coroutines.
#[lang = "maybe_uninit"]
Expand Down
6 changes: 3 additions & 3 deletions src/tools/tidy/src/alphabetical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::fmt::Display;
use std::iter::Peekable;
use std::path::Path;

use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
use crate::diagnostics::{CheckId, RunningCheck, TidyCtx};
use crate::walk::{filter_dirs, walk};

#[cfg(test)]
Expand Down Expand Up @@ -130,8 +130,8 @@ fn check_lines<'a>(
}
}

pub fn check(path: &Path, diag_ctx: DiagCtx) {
let mut check = diag_ctx.start_check(CheckId::new("alphabetical").path(path));
pub fn check(path: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check(CheckId::new("alphabetical").path(path));

let skip =
|path: &_, _is_dir| filter_dirs(path) || path.ends_with("tidy/src/alphabetical/tests.rs");
Expand Down
6 changes: 3 additions & 3 deletions src/tools/tidy/src/alphabetical/tests.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::path::Path;

use crate::alphabetical::check_lines;
use crate::diagnostics::DiagCtx;
use crate::diagnostics::{TidyCtx, TidyFlags};

#[track_caller]
fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) {
let diag_ctx = DiagCtx::new(Path::new("/"), false);
let mut check = diag_ctx.start_check("alphabetical-test");
let tidy_ctx = TidyCtx::new(Path::new("/"), false, TidyFlags::default());
let mut check = tidy_ctx.start_check("alphabetical-test");
check_lines(&name, lines.lines().enumerate(), &mut check);

assert_eq!(expected_bad, check.is_bad());
Expand Down
10 changes: 5 additions & 5 deletions src/tools/tidy/src/bins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ pub use os_impl::*;
mod os_impl {
use std::path::Path;

use crate::diagnostics::DiagCtx;
use crate::diagnostics::TidyCtx;

pub fn check_filesystem_support(_sources: &[&Path], _output: &Path) -> bool {
return false;
}

pub fn check(_path: &Path, _diag_ctx: DiagCtx) {}
pub fn check(_path: &Path, _tidy_ctx: TidyCtx) {}
}

#[cfg(unix)]
Expand All @@ -38,7 +38,7 @@ mod os_impl {

use FilesystemSupport::*;

use crate::diagnostics::DiagCtx;
use crate::diagnostics::TidyCtx;

fn is_executable(path: &Path) -> std::io::Result<bool> {
Ok(path.metadata()?.mode() & 0o111 != 0)
Expand Down Expand Up @@ -110,8 +110,8 @@ mod os_impl {
}

#[cfg(unix)]
pub fn check(path: &Path, diag_ctx: DiagCtx) {
let mut check = diag_ctx.start_check("bins");
pub fn check(path: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check("bins");

use std::ffi::OsStr;

Expand Down
6 changes: 3 additions & 3 deletions src/tools/tidy/src/debug_artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

use std::path::Path;

use crate::diagnostics::{CheckId, DiagCtx};
use crate::diagnostics::{CheckId, TidyCtx};
use crate::walk::{filter_dirs, filter_not_rust, walk};

const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test";

pub fn check(test_dir: &Path, diag_ctx: DiagCtx) {
let mut check = diag_ctx.start_check(CheckId::new("debug_artifacts").path(test_dir));
pub fn check(test_dir: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check(CheckId::new("debug_artifacts").path(test_dir));

walk(
test_dir,
Expand Down
7 changes: 4 additions & 3 deletions src/tools/tidy/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use build_helper::ci::CiEnv;
use cargo_metadata::semver::Version;
use cargo_metadata::{Metadata, Package, PackageId};

use crate::diagnostics::{DiagCtx, RunningCheck};
use crate::diagnostics::{RunningCheck, TidyCtx};

#[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"]
mod proc_macro_deps;
Expand Down Expand Up @@ -615,8 +615,9 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
///
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
/// to the cargo executable.
pub fn check(root: &Path, cargo: &Path, bless: bool, diag_ctx: DiagCtx) {
let mut check = diag_ctx.start_check("deps");
pub fn check(root: &Path, cargo: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check("deps");
let bless = tidy_ctx.is_bless_enabled();

let mut checked_runtime_licenses = false;

Expand Down
57 changes: 44 additions & 13 deletions src/tools/tidy/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,59 @@ use std::sync::{Arc, Mutex};

use termcolor::{Color, WriteColor};

#[derive(Clone, Default)]
///CLI flags used by tidy.
pub struct TidyFlags {
///Applies style and formatting changes during a tidy run.
bless: bool,
}

impl TidyFlags {
pub fn new(cfg_args: &[String]) -> Self {
let mut flags = Self::default();

for arg in cfg_args {
match arg.as_str() {
"--bless" => flags.bless = true,
_ => continue,
}
}
flags
}
}

/// Collects diagnostics from all tidy steps, and contains shared information
/// that determines how should message and logs be presented.
///
/// Since checks are executed in parallel, the context is internally synchronized, to avoid
/// all checks to lock it explicitly.
#[derive(Clone)]
pub struct DiagCtx(Arc<Mutex<DiagCtxInner>>);
pub struct TidyCtx {
tidy_flags: TidyFlags,
diag_ctx: Arc<Mutex<DiagCtxInner>>,
}

impl TidyCtx {
pub fn new(root_path: &Path, verbose: bool, tidy_flags: TidyFlags) -> Self {
Self {
diag_ctx: Arc::new(Mutex::new(DiagCtxInner {
running_checks: Default::default(),
finished_checks: Default::default(),
root_path: root_path.to_path_buf(),
verbose,
})),
tidy_flags,
}
}

impl DiagCtx {
pub fn new(root_path: &Path, verbose: bool) -> Self {
Self(Arc::new(Mutex::new(DiagCtxInner {
running_checks: Default::default(),
finished_checks: Default::default(),
root_path: root_path.to_path_buf(),
verbose,
})))
pub fn is_bless_enabled(&self) -> bool {
self.tidy_flags.bless
}

pub fn start_check<Id: Into<CheckId>>(&self, id: Id) -> RunningCheck {
let mut id = id.into();

let mut ctx = self.0.lock().unwrap();
let mut ctx = self.diag_ctx.lock().unwrap();

// Shorten path for shorter diagnostics
id.path = match id.path {
Expand All @@ -38,14 +69,14 @@ impl DiagCtx {
RunningCheck {
id,
bad: false,
ctx: self.0.clone(),
ctx: self.diag_ctx.clone(),
#[cfg(test)]
errors: vec![],
}
}

pub fn into_failed_checks(self) -> Vec<FinishedCheck> {
let ctx = Arc::into_inner(self.0).unwrap().into_inner().unwrap();
let ctx = Arc::into_inner(self.diag_ctx).unwrap().into_inner().unwrap();
assert!(ctx.running_checks.is_empty(), "Some checks are still running");
ctx.finished_checks.into_iter().filter(|c| c.bad).collect()
}
Expand Down Expand Up @@ -151,7 +182,7 @@ impl RunningCheck {
/// Useful if you want to run some functions from tidy without configuring
/// diagnostics.
pub fn new_noop() -> Self {
let ctx = DiagCtx::new(Path::new(""), false);
let ctx = TidyCtx::new(Path::new(""), false, TidyFlags::default());
ctx.start_check("noop")
}

Expand Down
6 changes: 3 additions & 3 deletions src/tools/tidy/src/edition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

use std::path::Path;

use crate::diagnostics::{CheckId, DiagCtx};
use crate::diagnostics::{CheckId, TidyCtx};
use crate::walk::{filter_dirs, walk};

pub fn check(path: &Path, diag_ctx: DiagCtx) {
let mut check = diag_ctx.start_check(CheckId::new("edition").path(path));
pub fn check(path: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check(CheckId::new("edition").path(path));
walk(path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| {
let file = entry.path();
let filename = file.file_name().unwrap();
Expand Down
6 changes: 3 additions & 3 deletions src/tools/tidy/src/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::path::Path;

use regex::Regex;

use crate::diagnostics::{DiagCtx, RunningCheck};
use crate::diagnostics::{RunningCheck, TidyCtx};
use crate::walk::{filter_dirs, walk, walk_many};

const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/lib.rs";
Expand All @@ -36,8 +36,8 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E07
const IGNORE_UI_TEST_CHECK: &[&str] =
&["E0461", "E0465", "E0514", "E0554", "E0640", "E0717", "E0729"];

pub fn check(root_path: &Path, search_paths: &[&Path], ci_info: &crate::CiInfo, diag_ctx: DiagCtx) {
let mut check = diag_ctx.start_check("error_codes");
pub fn check(root_path: &Path, search_paths: &[&Path], ci_info: &crate::CiInfo, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check("error_codes");

// Check that no error code explanation was removed.
check_removed_error_code_explanation(ci_info, &mut check);
Expand Down
6 changes: 3 additions & 3 deletions src/tools/tidy/src/extdeps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fs;
use std::path::Path;

use crate::deps::WorkspaceInfo;
use crate::diagnostics::DiagCtx;
use crate::diagnostics::TidyCtx;

/// List of allowed sources for packages.
const ALLOWED_SOURCES: &[&str] = &[
Expand All @@ -15,8 +15,8 @@ const ALLOWED_SOURCES: &[&str] = &[

/// Checks for external package sources. `root` is the path to the directory that contains the
/// workspace `Cargo.toml`.
pub fn check(root: &Path, diag_ctx: DiagCtx) {
let mut check = diag_ctx.start_check("extdeps");
pub fn check(root: &Path, tidy_ctx: TidyCtx) {
let mut check = tidy_ctx.start_check("extdeps");

for &WorkspaceInfo { path, submodules, .. } in crate::deps::WORKSPACES {
if crate::deps::has_missing_submodule(root, submodules) {
Expand Down
Loading
Loading