Auto merge of #132005 - matthiaskrgr:rollup-ced4upi, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #130350 (stabilize Strict Provenance and Exposed Provenance APIs)
 - #131737 (linkchecker: add a reminder on broken links to add new/renamed pages to `SUMMARY.md` for mdBooks)
 - #131991 (test: Add test for trait in FQS cast, issue #98565)
 - #131997 (Make `rustc_abi` compile on stable again)
 - #131999 (Improve test coverage for `unit_bindings` lint)
 - #132001 (fix coherence error for very large tuples™)
 - #132003 (update ABI compatibility docs for new option-like rules)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-10-21 17:33:42 +00:00
commit 31e102c509
107 changed files with 624 additions and 571 deletions

View File

@ -3,18 +3,23 @@ mod abi {
pub(crate) use crate::Variants;
}
#[cfg(feature = "nightly")]
use rustc_macros::HashStable_Generic;
use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
#[cfg(feature = "nightly")]
use crate::{Abi, FieldsShape, TyAbiInterface, TyAndLayout};
use crate::{Align, HasDataLayout, Size};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum RegKind {
Integer,
Float,
Vector,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Reg {
pub kind: RegKind,
pub size: Size,
@ -108,15 +113,8 @@ impl HomogeneousAggregate {
}
}
#[cfg(feature = "nightly")]
impl<'a, Ty> TyAndLayout<'a, Ty> {
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
pub fn is_aggregate(&self) -> bool {
match self.abi {
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
}
}
/// Returns `Homogeneous` if this layout is an aggregate containing fields of
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
/// special-cased in ABIs.

View File

@ -11,8 +11,10 @@ use crate::{
Variants, WrappingRange,
};
#[cfg(feature = "nightly")]
mod ty;
#[cfg(feature = "nightly")]
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
// A variant is absent if it's uninhabited and only has ZST fields.

View File

@ -29,14 +29,14 @@ mod layout;
mod tests;
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
pub use layout::{
FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface,
TyAndLayout, VariantIdx,
};
#[cfg(feature = "nightly")]
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
pub use layout::{LayoutCalculator, LayoutCalculatorError};
/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in `rustc_middle`.
#[cfg(feature = "nightly")]
pub trait HashStableContext {}
#[derive(Clone, Copy, PartialEq, Eq, Default)]
@ -1644,6 +1644,14 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
}
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
pub fn is_aggregate(&self) -> bool {
match self.abi {
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
}
}
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
let size = scalar.size(cx);

View File

@ -23,7 +23,6 @@
#![feature(maybe_uninit_slice)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end

View File

@ -11,7 +11,6 @@
#![feature(let_chains)]
#![feature(negative_impls)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![warn(unreachable_pub)]

View File

@ -361,12 +361,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty),
(Pointer(..), Int(..)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
bx.ptrtoint(imm, to_backend_ty)
}
(Float(_), Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
}
(Pointer(..), Float(_)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
bx.bitcast(int_imm, to_backend_ty)
}

View File

@ -10,7 +10,6 @@
#![feature(never_type)]
#![feature(rustdoc_internals)]
#![feature(slice_ptr_get)]
#![feature(strict_provenance)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(unqualified_local_imports)]

View File

@ -33,7 +33,6 @@
#![feature(ptr_alignment_type)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![feature(test)]
#![feature(thread_id_value)]
#![feature(type_alias_impl_trait)]

View File

@ -595,7 +595,7 @@ declare_features! (
/// Allows attributes on expressions and non-item statements.
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
/// Allows lints part of the strict provenance effort.
(unstable, strict_provenance, "1.61.0", Some(95228)),
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
/// Allows string patterns to dereference values to match them.
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
/// Allows the use of `#[target_feature]` on safe functions.

View File

@ -2667,7 +2667,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(strict_provenance)]
/// #![warn(fuzzy_provenance_casts)]
///
/// fn main() {
@ -2701,7 +2700,7 @@ declare_lint! {
pub FUZZY_PROVENANCE_CASTS,
Allow,
"a fuzzy integer to pointer cast is used",
@feature_gate = strict_provenance;
@feature_gate = strict_provenance_lints;
}
declare_lint! {
@ -2711,7 +2710,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(strict_provenance)]
/// #![warn(lossy_provenance_casts)]
///
/// fn main() {
@ -2747,7 +2745,7 @@ declare_lint! {
pub LOSSY_PROVENANCE_CASTS,
Allow,
"a lossy pointer to integer cast is used",
@feature_gate = strict_provenance;
@feature_gate = strict_provenance_lints;
}
declare_lint! {

View File

@ -56,7 +56,6 @@
#![feature(ptr_alignment_type)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![feature(trait_upcasting)]
#![feature(trusted_len)]
#![feature(try_blocks)]

View File

@ -16,7 +16,7 @@ use rustc_type_ir::fold::TypeFoldable;
use rustc_type_ir::inherent::*;
use rustc_type_ir::relate::solver_relating::RelateExt;
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner};
use tracing::{instrument, trace};
use tracing::{debug, instrument, trace};
use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
use crate::delegate::SolverDelegate;
@ -165,13 +165,23 @@ where
// HACK: We bail with overflow if the response would have too many non-region
// inference variables. This tends to only happen if we encounter a lot of
// ambiguous alias types which get replaced with fresh inference variables
// during generalization. This prevents a hang in nalgebra.
let num_non_region_vars = canonical.variables.iter().filter(|c| !c.is_region()).count();
// during generalization. This prevents hangs caused by an exponential blowup,
// see tests/ui/traits/next-solver/coherence-alias-hang.rs.
//
// We don't do so for `NormalizesTo` goals as we erased the expected term and
// bailing with overflow here would prevent us from detecting a type-mismatch,
// causing a coherence error in diesel, see #131969. We still bail with verflow
// when later returning from the parent AliasRelate goal.
if !self.is_normalizes_to_goal {
let num_non_region_vars =
canonical.variables.iter().filter(|c| !c.is_region() && c.is_existential()).count();
if num_non_region_vars > self.cx().recursion_limit() {
debug!(?num_non_region_vars, "too many inference variables -> overflow");
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow {
suggest_increasing_limit: true,
}));
}
}
Ok(canonical)
}

View File

@ -1913,7 +1913,7 @@ symbols! {
str_trim,
str_trim_end,
str_trim_start,
strict_provenance,
strict_provenance_lints,
string_as_mut_str,
string_as_str,
string_deref_patterns,

View File

@ -298,6 +298,7 @@ fn equate_impl_headers<'tcx>(
}
/// The result of [fn impl_intersection_has_impossible_obligation].
#[derive(Debug)]
enum IntersectionHasImpossibleObligations<'tcx> {
Yes,
No {
@ -328,6 +329,7 @@ enum IntersectionHasImpossibleObligations<'tcx> {
/// of the two impls above to be empty.
///
/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
#[instrument(level = "debug", skip(selcx), ret)]
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligations: &'a [PredicateObligation<'tcx>],

View File

@ -4,7 +4,8 @@
#![feature(iter_next_chunk)]
#![feature(repr_simd)]
#![feature(slice_partition_dedup)]
#![feature(strict_provenance)]
#![cfg_attr(bootstrap, feature(strict_provenance))]
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
#![feature(test)]
#![deny(fuzzy_provenance_casts)]

View File

@ -147,7 +147,6 @@
#![feature(slice_range)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(strict_provenance)]
#![feature(trusted_fused)]
#![feature(trusted_len)]
#![feature(trusted_random_access)]
@ -162,6 +161,8 @@
//
// Language features:
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(strict_provenance))]
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
#![cfg_attr(not(test), feature(coroutine_trait))]
#![cfg_attr(test, feature(panic_update_hook))]
#![cfg_attr(test, feature(test))]

View File

@ -32,7 +32,8 @@
#![feature(panic_update_hook)]
#![feature(pointer_is_aligned_to)]
#![feature(thin_box)]
#![feature(strict_provenance)]
#![cfg_attr(bootstrap, feature(strict_provenance))]
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
#![feature(drain_keep_rest)]
#![feature(local_waker)]
#![feature(vec_pop_if)]

View File

@ -2794,7 +2794,6 @@ where
/// #![feature(is_val_statically_known)]
/// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// #![feature(strict_provenance)]
/// use std::intrinsics::is_val_statically_known;
///
/// fn foo(x: &i32) -> bool {

View File

@ -163,7 +163,6 @@
#![feature(str_internals)]
#![feature(str_split_inclusive_remainder)]
#![feature(str_split_remainder)]
#![feature(strict_provenance)]
#![feature(ub_checks)]
#![feature(unchecked_neg)]
#![feature(unchecked_shifts)]
@ -174,6 +173,8 @@
//
// Language features:
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(strict_provenance))]
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
#![feature(abi_unadjusted)]
#![feature(adt_const_params)]
#![feature(allow_internal_unsafe)]

View File

@ -1784,9 +1784,11 @@ mod prim_ref {}
/// unique field that doesn't have size 0 and alignment 1 (if there is such a field).
/// - `i32` is ABI-compatible with `NonZero<i32>`, and similar for all other integer types.
/// - If `T` is guaranteed to be subject to the [null pointer
/// optimization](option/index.html#representation), then `T` and `Option<T>` are ABI-compatible.
/// Furthermore, if `U` satisfies the requirements [outlined here](result/index.html#representation),
/// then `T` and `Result<T, U>` and `Result<U, T>` are all ABI-compatible.
/// optimization](option/index.html#representation), and `E` is an enum satisfying the following
/// requirements, then `T` and `E` are ABI-compatible. Such an enum `E` is called "option-like".
/// - The enum `E` has exactly two variants.
/// - One variant has exactly one field, of type `T`.
/// - All fields of the other variant are zero-sized with 1-byte alignment.
///
/// Furthermore, ABI compatibility satisfies the following general properties:
///

View File

@ -137,10 +137,11 @@ impl<T: ?Sized> *const T {
/// Gets the "address" portion of the pointer.
///
/// This is similar to `self as usize`, which semantically discards *provenance* and
/// *address-space* information. However, unlike `self as usize`, casting the returned address
/// back to a pointer yields a [pointer without provenance][without_provenance], which is undefined behavior to dereference. To
/// properly restore the lost information and obtain a dereferenceable pointer, use
/// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of
/// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that
/// casting the returned address back to a pointer yields a [pointer without
/// provenance][without_provenance], which is undefined behavior to dereference. To properly
/// restore the lost information and obtain a dereferenceable pointer, use
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
///
/// If using those APIs is not possible because there is no way to preserve a pointer with the
@ -155,90 +156,81 @@ impl<T: ?Sized> *const T {
/// perform a change of representation to produce a value containing only the address
/// portion of the pointer. What that means is up to the platform to define.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment, and as such
/// might change in the future (including possibly weakening this so it becomes wholly
/// equivalent to `self as usize`). See the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn addr(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
// A pointer-to-integer transmute currently has exactly the right semantics: it returns the
// address without exposing the provenance. Note that this is *not* a stable guarantee about
// transmute semantics, it relies on sysroot crates having special status.
// SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
// provenance).
unsafe { mem::transmute(self.cast::<()>()) }
}
/// Exposes the "provenance" part of the pointer for future use in
/// [`with_exposed_provenance`][] and returns the "address" portion.
/// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in
/// [`with_exposed_provenance`] and returns the "address" portion.
///
/// This is equivalent to `self as usize`, which semantically discards *provenance* and
/// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
/// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
/// later call [`with_exposed_provenance`][] to reconstitute the original pointer including its
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
/// This is equivalent to `self as usize`, which semantically discards provenance information.
/// Furthermore, this (like the `as` cast) has the implicit side-effect of marking the
/// provenance as 'exposed', so on platforms that support it you can later call
/// [`with_exposed_provenance`] to reconstitute the original pointer including its provenance.
///
/// Using this method means that code is *not* following [Strict
/// Provenance][super#strict-provenance] rules. Supporting
/// [`with_exposed_provenance`][] complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`addr`][pointer::addr] wherever possible.
/// Due to its inherent ambiguity, [`with_exposed_provenance`] may not be supported by tools
/// that help you to stay conformant with the Rust memory model. It is recommended to use
/// [Strict Provenance][crate::ptr#strict-provenance] APIs such as [`with_addr`][pointer::with_addr]
/// wherever possible, in which case [`addr`][pointer::addr] should be used instead of `expose_provenance`.
///
/// On most platforms this will produce a value with the same bytes as the original pointer,
/// because all the bytes are dedicated to describing the address. Platforms which need to store
/// additional information in the pointer may not support this operation, since the 'expose'
/// side-effect which is required for [`with_exposed_provenance`][] to work is typically not
/// side-effect which is required for [`with_exposed_provenance`] to work is typically not
/// available.
///
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API.
///
/// [`with_exposed_provenance`]: with_exposed_provenance
#[must_use]
#[inline(always)]
#[unstable(feature = "exposed_provenance", issue = "95228")]
#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn expose_provenance(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
self.cast::<()>() as usize
}
/// Creates a new pointer with the given address.
/// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of
/// `self`.
///
/// This performs the same operation as an `addr as ptr` cast, but copies
/// the *address-space* and *provenance* of `self` to the new pointer.
/// This allows us to dynamically preserve and propagate this important
/// information in a way that is otherwise impossible with a unary cast.
/// This is similar to a `addr as *const T` cast, but copies
/// the *provenance* of `self` to the new pointer.
/// This avoids the inherent ambiguity of the unary cast.
///
/// This is equivalent to using [`wrapping_offset`][pointer::wrapping_offset] to offset
/// `self` to the given address, and therefore has all the same capabilities and restrictions.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn with_addr(self, addr: usize) -> Self {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
//
// In the mean-time, this operation is defined to be "as if" it was
// a wrapping_offset, so we can emulate it as such. This should properly
// restore pointer provenance even under today's compiler.
// This should probably be an intrinsic to avoid doing any sort of arithmetic, but
// meanwhile, we can implement it with `wrapping_offset`, which preserves the pointer's
// provenance.
let self_addr = self.addr() as isize;
let dest_addr = addr as isize;
let offset = dest_addr.wrapping_sub(self_addr);
// This is the canonical desugaring of this operation
self.wrapping_byte_offset(offset)
}
/// Creates a new pointer by mapping `self`'s address to a new one.
/// Creates a new pointer by mapping `self`'s address to a new one, preserving the
/// [provenance][crate::ptr#provenance] of `self`.
///
/// This is a convenience for [`with_addr`][pointer::with_addr], see that method for details.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
self.with_addr(f(self.addr()))
}
@ -379,7 +371,7 @@ impl<T: ?Sized> *const T {
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
@ -560,7 +552,7 @@ impl<T: ?Sized> *const T {
/// ## Examples
///
/// ```
/// #![feature(ptr_mask, strict_provenance)]
/// #![feature(ptr_mask)]
/// let v = 17_u32;
/// let ptr: *const u32 = &v;
///
@ -611,7 +603,7 @@ impl<T: ?Sized> *const T {
/// * `self` and `origin` must either
///
/// * point to the same address, or
/// * both be *derived from* a pointer to the same [allocated object], and the memory range between
/// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocated object], and the memory range between
/// the two pointers must be in bounds of that object. (See below for an example.)
///
/// * The distance between the pointers, in bytes, must be an exact multiple
@ -871,7 +863,7 @@ impl<T: ?Sized> *const T {
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
@ -978,7 +970,7 @@ impl<T: ?Sized> *const T {
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.

View File

@ -18,10 +18,11 @@
//! * For operations of [size zero][zst], *every* pointer is valid, including the [null] pointer.
//! The following points are only concerned with non-zero-sized accesses.
//! * A [null] pointer is *never* valid.
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
//! be *dereferenceable*: the memory range of the given size starting at the pointer must all be
//! within the bounds of a single allocated object. Note that in Rust,
//! every (stack-allocated) variable is considered a separate allocated object.
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer be
//! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocated
//! object] it is derived from; a pointer is dereferenceable if the memory range of the given size
//! starting at the pointer is entirely contained within the bounds of that allocated object. Note
//! that in Rust, every (stack-allocated) variable is considered a separate allocated object.
//! * All accesses performed by functions in this module are *non-atomic* in the sense
//! of [atomic operations] used to synchronize between threads. This means it is
//! undefined behavior to perform two concurrent accesses to the same location from different
@ -130,123 +131,130 @@
//!
//! [`null()`]: null
//!
//! # Strict Provenance
//!
//! **The following text is non-normative, insufficiently formal, and is an extremely strict
//! interpretation of provenance. It's ok if your code doesn't strictly conform to it.**
//!
//! [Strict Provenance][] is an experimental set of APIs that help tools that try
//! to validate the memory-safety of your program's execution. Notably this includes [Miri][]
//! and [CHERI][], which can detect when you access out of bounds memory or otherwise violate
//! Rust's memory model.
//!
//! Provenance must exist in some form for any programming
//! language compiled for modern computer architectures, but specifying a model for provenance
//! in a way that is useful to both compilers and programmers is an ongoing challenge.
//! The [Strict Provenance][] experiment seeks to explore the question: *what if we just said you
//! couldn't do all the nasty operations that make provenance so messy?*
//!
//! What APIs would have to be removed? What APIs would have to be added? How much would code
//! have to change, and is it worse or better now? Would any patterns become truly inexpressible?
//! Could we carve out special exceptions for those patterns? Should we?
//!
//! A secondary goal of this project is to see if we can disambiguate the many functions of
//! pointer<->integer casts enough for the definition of `usize` to be loosened so that it
//! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue
//! to conflate these notions). This would potentially make it possible to more efficiently
//! target platforms where pointers are larger than offsets, such as CHERI and maybe some
//! segmented architectures.
//!
//! ## Provenance
//!
//! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.**
//! # Provenance
//!
//! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial
//! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky"
//! and the freed memory gets reallocated before your read/write (in fact this is the
//! worst-case scenario, UAFs would be much less concerning if this didn't happen!).
//! To rationalize this claim, pointers need to somehow be *more* than just their addresses:
//! they must have provenance.
//! As another example, consider that [`wrapping_offset`] is documented to "remember"
//! the allocated object that the original pointer points to, even if it is offset far
//! outside the memory range occupied by that allocated object.
//! To rationalize claims like this, pointers need to somehow be *more* than just their addresses:
//! they must have **provenance**.
//!
//! When an allocation is created, that allocation has a unique Original Pointer. For alloc
//! APIs this is literally the pointer the call returns, and for local variables and statics,
//! this is the name of the variable/static. This is mildly overloading the term "pointer"
//! for the sake of brevity/exposition.
//! A pointer value in Rust semantically contains the following information:
//!
//! The Original Pointer for an allocation is guaranteed to have unique access to the entire
//! allocation and *only* that allocation. In this sense, an allocation can be thought of
//! as a "sandbox" that cannot be broken into or out of. *Provenance* is the permission
//! to access an allocation's sandbox and has both a *spatial* and *temporal* component:
//!
//! * Spatial: A range of bytes that the pointer is allowed to access.
//! * Temporal: The lifetime (of the allocation) that access to these bytes is tied to.
//!
//! Spatial provenance makes sure you don't go beyond your sandbox, while temporal provenance
//! makes sure that you can't "get lucky" after your permission to access some memory
//! has been revoked (either through deallocations or borrows expiring).
//!
//! Provenance is implicitly shared with all pointers transitively derived from
//! The Original Pointer through operations like [`offset`], borrowing, and pointer casts.
//! Some operations may *shrink* the derived provenance, limiting how much memory it can
//! access or how long it's valid for (i.e. borrowing a subfield and subslicing).
//!
//! Shrinking provenance cannot be undone: even if you "know" there is a larger allocation, you
//! can't derive a pointer with a larger provenance. Similarly, you cannot "recombine"
//! two contiguous provenances back into one (i.e. with a `fn merge(&[T], &[T]) -> &[T]`).
//!
//! A reference to a value always has provenance over exactly the memory that field occupies.
//! A reference to a slice always has provenance over exactly the range that slice describes.
//!
//! If an allocation is deallocated, all pointers with provenance to that allocation become
//! invalidated, and effectively lose their provenance.
//!
//! The strict provenance experiment is mostly only interested in exploring stricter *spatial*
//! provenance. In this sense it can be thought of as a subset of the more ambitious and
//! formal [Stacked Borrows][] research project, which is what tools like [Miri][] are based on.
//! In particular, Stacked Borrows is necessary to properly describe what borrows are allowed
//! to do and when they become invalidated. This necessarily involves much more complex
//! *temporal* reasoning than simply identifying allocations. Adjusting APIs and code
//! for the strict provenance experiment will also greatly help Stacked Borrows.
//!
//!
//! ## Pointer Vs Addresses
//!
//! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.**
//!
//! One of the largest historical issues with trying to define provenance is that programmers
//! freely convert between pointers and integers. Once you allow for this, it generally becomes
//! impossible to accurately track and preserve provenance information, and you need to appeal
//! to very complex and unreliable heuristics. But of course, converting between pointers and
//! integers is very useful, so what can we do?
//!
//! Also did you know WASM is actually a "Harvard Architecture"? As in function pointers are
//! handled completely differently from data pointers? And we kind of just shipped Rust on WASM
//! without really addressing the fact that we let you freely convert between function pointers
//! and data pointers, because it mostly Just Works? Let's just put that on the "pointer casts
//! are dubious" pile.
//!
//! Strict Provenance attempts to square these circles by decoupling Rust's traditional conflation
//! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the
//! following information:
//!
//! * The **address-space** it is part of (e.g. "data" vs "code" in WASM).
//! * The **address** it points to, which can be represented by a `usize`.
//! * The **provenance** it has, defining the memory it has permission to access.
//! Provenance can be absent, in which case the pointer does not have permission to access any memory.
//! * The **provenance** it has, defining the memory it has permission to access. Provenance can be
//! absent, in which case the pointer does not have permission to access any memory.
//!
//! Under Strict Provenance, a `usize` *cannot* accurately represent a pointer, and converting from
//! a pointer to a `usize` is generally an operation which *only* extracts the address. It is
//! therefore *impossible* to construct a valid pointer from a `usize` because there is no way
//! to restore the address-space and provenance. In other words, pointer-integer-pointer
//! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable).
//! The exact structure of provenance is not yet specified, but the permission defined by a
//! pointer's provenance have a *spatial* component, a *temporal* component, and a *mutability*
//! component:
//!
//! The key insight to making this model *at all* viable is the [`with_addr`][] method:
//! * Spatial: The set of memory addresses that the pointer is allowed to access.
//! * Temporal: The timespan during which the pointer is allowed to access those memory addresses.
//! * Mutability: Whether the pointer may only access the memory for reads, or also access it for
//! writes. Note that this can interact with the other components, e.g. a pointer might permit
//! mutation only for a subset of addresses, or only for a subset of its maximal timespan.
//!
//! When an [allocated object] is created, it has a unique Original Pointer. For alloc
//! APIs this is literally the pointer the call returns, and for local variables and statics,
//! this is the name of the variable/static. (This is mildly overloading the term "pointer"
//! for the sake of brevity/exposition.)
//!
//! The Original Pointer for an allocated object has provenance that constrains the *spatial*
//! permissions of this pointer to the memory range of the allocation, and the *temporal*
//! permissions to the lifetime of the allocation. Provenance is implicitly inherited by all
//! pointers transitively derived from the Original Pointer through operations like [`offset`],
//! borrowing, and pointer casts. Some operations may *shrink* the permissions of the derived
//! provenance, limiting how much memory it can access or how long it's valid for (i.e. borrowing a
//! subfield and subslicing can shrink the spatial component of provenance, and all borrowing can
//! shrink the temporal component of provenance). However, no operation can ever *grow* the
//! permissions of the derived provenance: even if you "know" there is a larger allocation, you
//! can't derive a pointer with a larger provenance. Similarly, you cannot "recombine" two
//! contiguous provenances back into one (i.e. with a `fn merge(&[T], &[T]) -> &[T]`).
//!
//! A reference to a place always has provenance over at least the memory that place occupies.
//! A reference to a slice always has provenance over at least the range that slice describes.
//! Whether and when exactly the provenance of a reference gets "shrunk" to *exactly* fit
//! the memory it points to is not yet determined.
//!
//! A *shared* reference only ever has provenance that permits reading from memory,
//! and never permits writes, except inside [`UnsafeCell`].
//!
//! Provenance can affect whether a program has undefined behavior:
//!
//! * It is undefined behavior to access memory through a pointer that does not have provenance over
//! that memory. Note that a pointer "at the end" of its provenance is not actually outside its
//! provenance, it just has 0 bytes it can load/store. Zero-sized accesses do not require any
//! provenance since they access an empty range of memory.
//!
//! * It is undefined behavior to [`offset`] a pointer across a memory range that is not contained
//! in the allocated object it is derived from, or to [`offset_from`] two pointers not derived
//! from the same allocated object. Provenance is used to say what exactly "derived from" even
//! means: the lineage of a pointer is traced back to the Original Pointer it descends from, and
//! that identifies the relevant allocated object. In particular, it's always UB to offset a
//! pointer derived from something that is now deallocated, except if the offset is 0.
//!
//! But it *is* still sound to:
//!
//! * Create a pointer without provenance from just an address (see [`ptr::dangling`]). Such a
//! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be
//! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be
//! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for
//! fun" as long as you don't use operations on it which require it to be valid (non-zero-sized
//! offset, read, write, etc).
//!
//! * Forge an allocation of size zero at any sufficiently aligned non-null address.
//! i.e. the usual "ZSTs are fake, do what you want" rules apply.
//!
//! * [`wrapping_offset`] a pointer outside its provenance. This includes pointers
//! which have "no" provenance. In particular, this makes it sound to do pointer tagging tricks.
//!
//! * Compare arbitrary pointers by address. Pointer comparison ignores provenance and addresses
//! *are* just integers, so there is always a coherent answer, even if the pointers are dangling
//! or from different provenances. Note that if you get "lucky" and notice that a pointer at the
//! end of one allocated object is the "same" address as the start of another allocated object,
//! anything you do with that fact is *probably* going to be gibberish. The scope of that
//! gibberish is kept under control by the fact that the two pointers *still* aren't allowed to
//! access the other's allocation (bytes), because they still have different provenance.
//!
//! Note that the full definition of provenance in Rust is not decided yet, as this interacts
//! with the as-yet undecided [aliasing] rules.
//!
//! ## Pointers Vs Integers
//!
//! From this discussion, it becomes very clear that a `usize` *cannot* accurately represent a pointer,
//! and converting from a pointer to a `usize` is generally an operation which *only* extracts the
//! address. Converting this address back into pointer requires somehow answering the question:
//! which provenance should the resulting pointer have?
//!
//! Rust provides two ways of dealing with this situation: *Strict Provenance* and *Exposed Provenance*.
//!
//! Note that a pointer *can* represent a `usize` (via [`without_provenance`]), so the right type to
//! use in situations where a value is "sometimes a pointer and sometimes a bare `usize`" is a
//! pointer type.
//!
//! ## Strict Provenance
//!
//! "Strict Provenance" refers to a set of APIs designed to make working with provenance more
//! explicit. They are intended as substitutes for casting a pointer to an integer and back.
//!
//! Entirely avoiding integer-to-pointer casts successfully side-steps the inherent ambiguity of
//! that operation. This benefits compiler optimizations, and it is pretty much a requirement for
//! using tools like [Miri] and architectures like [CHERI] that aim to detect and diagnose pointer
//! misuse.
//!
//! The key insight to making programming without integer-to-pointer casts *at all* viable is the
//! [`with_addr`] method:
//!
//! ```text
//! /// Creates a new pointer with the given address.
//! ///
//! /// This performs the same operation as an `addr as ptr` cast, but copies
//! /// the *address-space* and *provenance* of `self` to the new pointer.
//! /// the *provenance* of `self` to the new pointer.
//! /// This allows us to dynamically preserve and propagate this important
//! /// information in a way that is otherwise impossible with a unary cast.
//! ///
@ -257,23 +265,21 @@
//!
//! So you're still able to drop down to the address representation and do whatever
//! clever bit tricks you want *as long as* you're able to keep around a pointer
//! into the allocation you care about that can "reconstitute" the other parts of the pointer.
//! into the allocation you care about that can "reconstitute" the provenance.
//! Usually this is very easy, because you only are taking a pointer, messing with the address,
//! and then immediately converting back to a pointer. To make this use case more ergonomic,
//! we provide the [`map_addr`][] method.
//! we provide the [`map_addr`] method.
//!
//! To help make it clear that code is "following" Strict Provenance semantics, we also provide an
//! [`addr`][] method which promises that the returned address is not part of a
//! pointer-usize-pointer roundtrip. In the future we may provide a lint for pointer<->integer
//! [`addr`] method which promises that the returned address is not part of a
//! pointer-integer-pointer roundtrip. In the future we may provide a lint for pointer<->integer
//! casts to help you audit if your code conforms to strict provenance.
//!
//!
//! ## Using Strict Provenance
//! ### Using Strict Provenance
//!
//! Most code needs no changes to conform to strict provenance, as the only really concerning
//! operation that *wasn't* obviously already Undefined Behaviour is casts from usize to a
//! pointer. For code which *does* cast a `usize` to a pointer, the scope of the change depends
//! on exactly what you're doing.
//! operation is casts from usize to a pointer. For code which *does* cast a `usize` to a pointer,
//! the scope of the change depends on exactly what you're doing.
//!
//! In general, you just need to make sure that if you want to convert a `usize` address to a
//! pointer and then use that pointer to read/write memory, you need to keep around a pointer
@ -284,8 +290,6 @@
//! represent the tagged pointer as an actual pointer and not a `usize`*. For instance:
//!
//! ```
//! #![feature(strict_provenance)]
//!
//! unsafe {
//! // A flag we want to pack into our pointer
//! static HAS_DATA: usize = 0x1;
@ -314,122 +318,65 @@
//! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers,
//! we would like to know why, and what needs to be done to fix it.)
//!
//! Something more complicated and just generally *evil* like an XOR-List requires more significant
//! changes like allocating all nodes in a pre-allocated Vec or Arena and using a pointer
//! to the whole allocation to reconstitute the XORed addresses.
//!
//! Situations where a valid pointer *must* be created from just an address, such as baremetal code
//! accessing a memory-mapped interface at a fixed address, are an open question on how to support.
//! These situations *will* still be allowed, but we might require some kind of "I know what I'm
//! doing" annotation to explain the situation to the compiler. It's also possible they need no
//! special attention at all, because they're generally accessing memory outside the scope of
//! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile".
//!
//! Under [Strict Provenance] it is Undefined Behaviour to:
//!
//! * Access memory through a pointer that does not have provenance over that memory.
//!
//! * [`offset`] a pointer to or from an address it doesn't have provenance over.
//! This means it's always UB to offset a pointer derived from something deallocated,
//! even if the offset is 0. Note that a pointer "one past the end" of its provenance
//! is not actually outside its provenance, it just has 0 bytes it can load/store.
//!
//! But it *is* still sound to:
//!
//! * Create a pointer without provenance from just an address (see [`ptr::dangling`][]). Such a
//! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be
//! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be
//! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for
//! fun" as long as you don't use operations on it which require it to be valid (non-zero-sized
//! offset, read, write, etc).
//!
//! * Forge an allocation of size zero at any sufficiently aligned non-null address.
//! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies
//! for actual forgery (integers cast to pointers). If you borrow some struct's field
//! that *happens* to be zero-sized, the resulting pointer will have provenance tied to
//! that allocation, and it will still get invalidated if the allocation gets deallocated.
//! In the future we may introduce an API to make such a forged allocation explicit.
//!
//! * [`wrapping_offset`][] a pointer outside its provenance. This includes pointers
//! which have "no" provenance. Unfortunately there may be practical limits on this for a
//! particular platform, and it's an open question as to how to specify this (if at all).
//! Notably, [CHERI][] relies on a compression scheme that can't handle a
//! pointer getting offset "too far" out of bounds. If this happens, the address
//! returned by `addr` will be the value you expect, but the provenance will get invalidated
//! and using it to read/write will fault. The details of this are architecture-specific
//! and based on alignment, but the buffer on either side of the pointer's range is pretty
//! generous (think kilobytes, not bytes).
//!
//! * Compare arbitrary pointers by address. Addresses *are* just integers and so there is
//! always a coherent answer, even if the pointers are dangling or from different
//! address-spaces/provenances. Of course, comparing addresses from different address-spaces
//! is generally going to be *meaningless*, but so is comparing Kilograms to Meters, and Rust
//! doesn't prevent that either. Similarly, if you get "lucky" and notice that a pointer
//! one-past-the-end is the "same" address as the start of an unrelated allocation, anything
//! you do with that fact is *probably* going to be gibberish. The scope of that gibberish
//! is kept under control by the fact that the two pointers *still* aren't allowed to access
//! the other's allocation (bytes), because they still have different provenance.
//!
//! * Perform pointer tagging tricks. This falls out of [`wrapping_offset`] but is worth
//! mentioning in more detail because of the limitations of [CHERI][]. Low-bit tagging
//! is very robust, and often doesn't even go out of bounds because types ensure
//! size >= align (and over-aligning actually gives CHERI more flexibility). Anything
//! more complex than this rapidly enters "extremely platform-specific" territory as
//! certain things may or may not be allowed based on specific supported operations.
//! For instance, ARM explicitly supports high-bit tagging, and so CHERI on ARM inherits
//! that and should support it.
//! accessing a memory-mapped interface at a fixed address, cannot currently be handled with strict
//! provenance APIs and should use [exposed provenance](#exposed-provenance).
//!
//! ## Exposed Provenance
//!
//! **This section is *non-normative* and is an extension to the [Strict Provenance] experiment.**
//!
//! As discussed above, pointer-usize-pointer roundtrips are not possible under [Strict Provenance].
//! As discussed above, integer-to-pointer casts are not possible with Strict Provenance APIs.
//! This is by design: the goal of Strict Provenance is to provide a clear specification that we are
//! confident can be formalized unambiguously and can be subject to precise formal reasoning.
//! Integer-to-pointer casts do not (currently) have such a clear specification.
//!
//! However, there exist situations where pointer-usize-pointer roundtrips cannot be avoided, or
//! However, there exist situations where integer-to-pointer casts cannot be avoided, or
//! where avoiding them would require major refactoring. Legacy platform APIs also regularly assume
//! that `usize` can capture all the information that makes up a pointer. The goal of Strict
//! Provenance is not to rule out such code; the goal is to put all the *other* pointer-manipulating
//! code onto a more solid foundation. Strict Provenance is about improving the situation where
//! possible (all the code that can be written with Strict Provenance) without making things worse
//! for situations where Strict Provenance is insufficient.
//! that `usize` can capture all the information that makes up a pointer.
//! Bare-metal platforms can also require the synthesis of a pointer "out of thin air" without
//! anywhere to obtain proper provenance from.
//!
//! For these situations, there is a highly experimental extension to Strict Provenance called
//! *Exposed Provenance*. This extension permits pointer-usize-pointer roundtrips. However, its
//! semantics are on much less solid footing than Strict Provenance, and at this point it is not yet
//! clear where a satisfying unambiguous semantics can be defined for Exposed Provenance.
//! Furthermore, Exposed Provenance will not work (well) with tools like [Miri] and [CHERI].
//! Rust's model for dealing with integer-to-pointer casts is called *Exposed Provenance*. However,
//! the semantics of Exposed Provenance are on much less solid footing than Strict Provenance, and
//! at this point it is not yet clear whether a satisfying unambiguous semantics can be defined for
//! Exposed Provenance. (If that sounds bad, be reassured that other popular languages that provide
//! integer-to-pointer casts are not faring any better.) Furthermore, Exposed Provenance will not
//! work (well) with tools like [Miri] and [CHERI].
//!
//! Exposed Provenance is provided by the [`expose_provenance`] and [`with_exposed_provenance`] methods,
//! which are meant to replace `as` casts between pointers and integers. [`expose_provenance`] is a lot like
//! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed'
//! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but
//! is not materialized in actual executions, except in tools like [Miri].) [`with_exposed_provenance`]
//! can be used to construct a pointer with one of these previously 'exposed' provenances.
//! [`with_exposed_provenance`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is
//! no indication of what the correct provenance for the returned pointer is -- and that is exactly
//! what makes pointer-usize-pointer roundtrips so tricky to rigorously specify! There is no
//! algorithm that decides which provenance will be used. You can think of this as "guessing" the
//! right provenance, and the guess will be "maximally in your favor", in the sense that if there is
//! any way to avoid undefined behavior, then that is the guess that will be taken. However, if
//! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will
//! be used, the program has undefined behavior.
//! which are equivalent to `as` casts between pointers and integers.
//! - [`expose_provenance`] is a lot like [`addr`], but additionally adds the provenance of the
//! pointer to a global list of 'exposed' provenances. (This list is purely conceptual, it exists
//! for the purpose of specifying Rust but is not materialized in actual executions, except in
//! tools like [Miri].)
//! Memory which is outside the control of the Rust abstract machine (MMIO registers, for example)
//! is always considered to be exposed, so long as this memory is disjoint from memory that will
//! be used by the abstract machine such as the stack, heap, and statics.
//! - [`with_exposed_provenance`] can be used to construct a pointer with one of these previously
//! 'exposed' provenances. [`with_exposed_provenance`] takes only `addr: usize` as arguments, so
//! unlike in [`with_addr`] there is no indication of what the correct provenance for the returned
//! pointer is -- and that is exactly what makes integer-to-pointer casts so tricky to rigorously
//! specify! The compiler will do its best to pick the right provenance for you, but currently we
//! cannot provide any guarantees about which provenance the resulting pointer will have. Only one
//! thing is clear: if there is *no* previously 'exposed' provenance that justifies the way the
//! returned pointer will be used, the program has undefined behavior.
//!
//! Using [`expose_provenance`] or [`with_exposed_provenance`] (or the `as` casts) means that code is
//! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to
//! determine how far one can get in Rust without the use of [`expose_provenance`] and
//! [`with_exposed_provenance`], and to encourage code to be written with Strict Provenance APIs only.
//! Maximizing the amount of such code is a major win for avoiding specification complexity and to
//! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the
//! confidence in (unsafe) Rust code.
//! If at all possible, we encourage code to be ported to [Strict Provenance] APIs, thus avoiding
//! the need for Exposed Provenance. Maximizing the amount of such code is a major win for avoiding
//! specification complexity and to facilitate adoption of tools like [CHERI] and [Miri] that can be
//! a big help in increasing the confidence in (unsafe) Rust code. However, we acknowledge that this
//! is not always possible, and offer Exposed Provenance as a way to explicit "opt out" of the
//! well-defined semantics of Strict Provenance, and "opt in" to the unclear semantics of
//! integer-to-pointer casts.
//!
//! [aliasing]: ../../nomicon/aliasing.html
//! [allocated object]: #allocated-object
//! [provenance]: #provenance
//! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
//! [ub]: ../../reference/behavior-considered-undefined.html
//! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts
//! [atomic operations]: crate::sync::atomic
//! [`offset`]: pointer::offset
//! [`offset_from`]: pointer::offset_from
//! [`wrapping_offset`]: pointer::wrapping_offset
//! [`with_addr`]: pointer::with_addr
//! [`map_addr`]: pointer::map_addr
@ -439,8 +386,8 @@
//! [`with_exposed_provenance`]: with_exposed_provenance
//! [Miri]: https://github.com/rust-lang/miri
//! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
//! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228
//! [Stacked Borrows]: https://plv.mpi-sws.org/rustbelt/stacked-borrows/
//! [Strict Provenance]: #strict-provenance
//! [`UnsafeCell`]: core::cell::UnsafeCell
#![stable(feature = "rust1", since = "1.0.0")]
// There are many unsafe functions taking pointers that don't dereference them.
@ -629,7 +576,7 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
from_raw_parts_mut(without_provenance_mut::<()>(0), ())
}
/// Creates a pointer with the given address and no provenance.
/// Creates a pointer with the given address and no [provenance][crate::ptr#provenance].
///
/// This is equivalent to `ptr::null().with_addr(addr)`.
///
@ -641,16 +588,15 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
/// This is different from `addr as *const T`, which creates a pointer that picks up a previously
/// exposed provenance. See [`with_exposed_provenance`] for more details on that operation.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn without_provenance<T>(addr: usize) -> *const T {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
// We use transmute rather than a cast so tools like Miri can tell that this
// is *not* the same as with_exposed_provenance.
// An int-to-pointer transmute currently has exactly the intended semantics: it creates a
// pointer without provenance. Note that this is *not* a stable guarantee about transmute
// semantics, it relies on sysroot crates having special status.
// SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
// pointer).
unsafe { mem::transmute(addr) }
@ -668,12 +614,12 @@ pub const fn without_provenance<T>(addr: usize) -> *const T {
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn dangling<T>() -> *const T {
without_provenance(mem::align_of::<T>())
}
/// Creates a pointer with the given address and no provenance.
/// Creates a pointer with the given address and no [provenance][crate::ptr#provenance].
///
/// This is equivalent to `ptr::null_mut().with_addr(addr)`.
///
@ -685,16 +631,15 @@ pub const fn dangling<T>() -> *const T {
/// This is different from `addr as *mut T`, which creates a pointer that picks up a previously
/// exposed provenance. See [`with_exposed_provenance_mut`] for more details on that operation.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
// We use transmute rather than a cast so tools like Miri can tell that this
// is *not* the same as with_exposed_provenance.
// An int-to-pointer transmute currently has exactly the intended semantics: it creates a
// pointer without provenance. Note that this is *not* a stable guarantee about transmute
// semantics, it relies on sysroot crates having special status.
// SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
// pointer).
unsafe { mem::transmute(addr) }
@ -712,96 +657,88 @@ pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn dangling_mut<T>() -> *mut T {
without_provenance_mut(mem::align_of::<T>())
}
/// Converts an address back to a pointer, picking up a previously 'exposed' provenance.
/// Converts an address back to a pointer, picking up some previously 'exposed'
/// [provenance][crate::ptr#provenance].
///
/// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the
/// returned pointer is that of *any* pointer that was previously exposed by passing it to
/// [`expose_provenance`][pointer::expose_provenance], or a `ptr as usize` cast. In addition, memory which is
/// outside the control of the Rust abstract machine (MMIO registers, for example) is always
/// considered to be exposed, so long as this memory is disjoint from memory that will be used by
/// the abstract machine such as the stack, heap, and statics.
/// This is fully equivalent to `addr as *const T`. The provenance of the returned pointer is that
/// of *some* pointer that was previously exposed by passing it to
/// [`expose_provenance`][pointer::expose_provenance], or a `ptr as usize` cast. In addition, memory
/// which is outside the control of the Rust abstract machine (MMIO registers, for example) is
/// always considered to be accessible with an exposed provenance, so long as this memory is disjoint
/// from memory that will be used by the abstract machine such as the stack, heap, and statics.
///
/// If there is no 'exposed' provenance that justifies the way this pointer will be used,
/// the program has undefined behavior. In particular, the aliasing rules still apply: pointers
/// and references that have been invalidated due to aliasing accesses cannot be used anymore,
/// even if they have been exposed!
/// The exact provenance that gets picked is not specified. The compiler will do its best to pick
/// the "right" provenance for you (whatever that may be), but currently we cannot provide any
/// guarantees about which provenance the resulting pointer will have -- and therefore there
/// is no definite specification for which memory the resulting pointer may access.
///
/// Note that there is no algorithm that decides which provenance will be used. You can think of this
/// as "guessing" the right provenance, and the guess will be "maximally in your favor", in the sense
/// that if there is any way to avoid undefined behavior (while upholding all aliasing requirements),
/// then that is the guess that will be taken.
/// If there is *no* previously 'exposed' provenance that justifies the way the returned pointer
/// will be used, the program has undefined behavior. In particular, the aliasing rules still apply:
/// pointers and references that have been invalidated due to aliasing accesses cannot be used
/// anymore, even if they have been exposed!
///
/// On platforms with multiple address spaces, it is your responsibility to ensure that the
/// address makes sense in the address space that this pointer will be used with.
///
/// Using this function means that code is *not* following [Strict
/// Provenance][self#strict-provenance] rules. "Guessing" a
/// suitable provenance complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`with_addr`][pointer::with_addr] wherever possible.
/// Due to its inherent ambiguity, this operation may not be supported by tools that help you to
/// stay conformant with the Rust memory model. It is recommended to use [Strict
/// Provenance][self#strict-provenance] APIs such as [`with_addr`][pointer::with_addr] wherever
/// possible.
///
/// On most platforms this will produce a value with the same bytes as the address. Platforms
/// which need to store additional information in a pointer may not support this operation,
/// since it is generally not possible to actually *compute* which provenance the returned
/// pointer has to pick up.
///
/// It is unclear whether this function can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance].
/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API.
#[must_use]
#[inline(always)]
#[unstable(feature = "exposed_provenance", issue = "95228")]
#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
pub fn with_exposed_provenance<T>(addr: usize) -> *const T
where
T: Sized,
{
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
pub fn with_exposed_provenance<T>(addr: usize) -> *const T {
addr as *const T
}
/// Converts an address back to a mutable pointer, picking up a previously 'exposed' provenance.
/// Converts an address back to a mutable pointer, picking up some previously 'exposed'
/// [provenance][crate::ptr#provenance].
///
/// This is a more rigorously specified alternative to `addr as *mut T`. The provenance of the
/// returned pointer is that of *any* pointer that was previously passed to
/// [`expose_provenance`][pointer::expose_provenance] or a `ptr as usize` cast. If there is no previously
/// 'exposed' provenance that justifies the way this pointer will be used, the program has undefined
/// behavior. Note that there is no algorithm that decides which provenance will be used. You can
/// think of this as "guessing" the right provenance, and the guess will be "maximally in your
/// favor", in the sense that if there is any way to avoid undefined behavior, then that is the
/// guess that will be taken.
/// This is fully equivalent to `addr as *mut T`. The provenance of the returned pointer is that
/// of *some* pointer that was previously exposed by passing it to
/// [`expose_provenance`][pointer::expose_provenance], or a `ptr as usize` cast. In addition, memory
/// which is outside the control of the Rust abstract machine (MMIO registers, for example) is
/// always considered to be accessible with an exposed provenance, so long as this memory is disjoint
/// from memory that will be used by the abstract machine such as the stack, heap, and statics.
///
/// On platforms with multiple address spaces, it is your responsibility to ensure that the
/// address makes sense in the address space that this pointer will be used with.
/// The exact provenance that gets picked is not specified. The compiler will do its best to pick
/// the "right" provenance for you (whatever that may be), but currently we cannot provide any
/// guarantees about which provenance the resulting pointer will have -- and therefore there
/// is no definite specification for which memory the resulting pointer may access.
///
/// Using this function means that code is *not* following [Strict
/// Provenance][self#strict-provenance] rules. "Guessing" a
/// suitable provenance complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`with_addr`][pointer::with_addr] wherever possible.
/// If there is *no* previously 'exposed' provenance that justifies the way the returned pointer
/// will be used, the program has undefined behavior. In particular, the aliasing rules still apply:
/// pointers and references that have been invalidated due to aliasing accesses cannot be used
/// anymore, even if they have been exposed!
///
/// Due to its inherent ambiguity, this operation may not be supported by tools that help you to
/// stay conformant with the Rust memory model. It is recommended to use [Strict
/// Provenance][self#strict-provenance] APIs such as [`with_addr`][pointer::with_addr] wherever
/// possible.
///
/// On most platforms this will produce a value with the same bytes as the address. Platforms
/// which need to store additional information in a pointer may not support this operation,
/// since it is generally not possible to actually *compute* which provenance the returned
/// pointer has to pick up.
///
/// It is unclear whether this function can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance].
/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API.
#[must_use]
#[inline(always)]
#[unstable(feature = "exposed_provenance", issue = "95228")]
#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T
where
T: Sized,
{
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
addr as *mut T
}

View File

@ -124,12 +124,12 @@ impl<T: ?Sized> *mut T {
/// Gets the "address" portion of the pointer.
///
/// This is similar to `self as usize`, which semantically discards *provenance* and
/// *address-space* information. However, unlike `self as usize`, casting the returned address
/// back to a pointer yields a [pointer without provenance][without_provenance_mut], which is undefined
/// behavior to dereference. To properly restore the lost information and obtain a
/// dereferenceable pointer, use [`with_addr`][pointer::with_addr] or
/// [`map_addr`][pointer::map_addr].
/// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of
/// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that
/// casting the returned address back to a pointer yields a [pointer without
/// provenance][without_provenance_mut], which is undefined behavior to dereference. To properly
/// restore the lost information and obtain a dereferenceable pointer, use
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
///
/// If using those APIs is not possible because there is no way to preserve a pointer with the
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
@ -143,89 +143,80 @@ impl<T: ?Sized> *mut T {
/// perform a change of representation to produce a value containing only the address
/// portion of the pointer. What that means is up to the platform to define.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment, and as such
/// might change in the future (including possibly weakening this so it becomes wholly
/// equivalent to `self as usize`). See the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn addr(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
// A pointer-to-integer transmute currently has exactly the right semantics: it returns the
// address without exposing the provenance. Note that this is *not* a stable guarantee about
// transmute semantics, it relies on sysroot crates having special status.
// SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
// provenance).
unsafe { mem::transmute(self.cast::<()>()) }
}
/// Exposes the "provenance" part of the pointer for future use in
/// [`with_exposed_provenance`][] and returns the "address" portion.
/// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in
/// [`with_exposed_provenance_mut`] and returns the "address" portion.
///
/// This is equivalent to `self as usize`, which semantically discards *provenance* and
/// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
/// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
/// later call [`with_exposed_provenance_mut`][] to reconstitute the original pointer including its
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
/// This is equivalent to `self as usize`, which semantically discards provenance information.
/// Furthermore, this (like the `as` cast) has the implicit side-effect of marking the
/// provenance as 'exposed', so on platforms that support it you can later call
/// [`with_exposed_provenance_mut`] to reconstitute the original pointer including its provenance.
///
/// Using this method means that code is *not* following [Strict
/// Provenance][super#strict-provenance] rules. Supporting
/// [`with_exposed_provenance_mut`][] complicates specification and reasoning and may not be supported
/// by tools that help you to stay conformant with the Rust memory model, so it is recommended
/// to use [`addr`][pointer::addr] wherever possible.
/// Due to its inherent ambiguity, [`with_exposed_provenance_mut`] may not be supported by tools
/// that help you to stay conformant with the Rust memory model. It is recommended to use
/// [Strict Provenance][crate::ptr#strict-provenance] APIs such as [`with_addr`][pointer::with_addr]
/// wherever possible, in which case [`addr`][pointer::addr] should be used instead of `expose_provenance`.
///
/// On most platforms this will produce a value with the same bytes as the original pointer,
/// because all the bytes are dedicated to describing the address. Platforms which need to store
/// additional information in the pointer may not support this operation, since the 'expose'
/// side-effect which is required for [`with_exposed_provenance_mut`][] to work is typically not
/// side-effect which is required for [`with_exposed_provenance_mut`] to work is typically not
/// available.
///
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API.
///
/// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut
#[inline(always)]
#[unstable(feature = "exposed_provenance", issue = "95228")]
#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn expose_provenance(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
self.cast::<()>() as usize
}
/// Creates a new pointer with the given address.
/// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of
/// `self`.
///
/// This performs the same operation as an `addr as ptr` cast, but copies
/// the *address-space* and *provenance* of `self` to the new pointer.
/// This allows us to dynamically preserve and propagate this important
/// information in a way that is otherwise impossible with a unary cast.
/// This is similar to a `addr as *mut T` cast, but copies
/// the *provenance* of `self` to the new pointer.
/// This avoids the inherent ambiguity of the unary cast.
///
/// This is equivalent to using [`wrapping_offset`][pointer::wrapping_offset] to offset
/// `self` to the given address, and therefore has all the same capabilities and restrictions.
///
/// This API and its claimed semantics are an extension to the Strict Provenance experiment,
/// see the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn with_addr(self, addr: usize) -> Self {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
//
// In the mean-time, this operation is defined to be "as if" it was
// a wrapping_offset, so we can emulate it as such. This should properly
// restore pointer provenance even under today's compiler.
// This should probably be an intrinsic to avoid doing any sort of arithmetic, but
// meanwhile, we can implement it with `wrapping_offset`, which preserves the pointer's
// provenance.
let self_addr = self.addr() as isize;
let dest_addr = addr as isize;
let offset = dest_addr.wrapping_sub(self_addr);
// This is the canonical desugaring of this operation
self.wrapping_byte_offset(offset)
}
/// Creates a new pointer by mapping `self`'s address to a new one.
/// Creates a new pointer by mapping `self`'s address to a new one, preserving the original
/// pointer's [provenance][crate::ptr#provenance].
///
/// This is a convenience for [`with_addr`][pointer::with_addr], see that method for details.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [module documentation][crate::ptr] for details.
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
self.with_addr(f(self.addr()))
}
@ -376,7 +367,7 @@ impl<T: ?Sized> *mut T {
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
@ -558,7 +549,7 @@ impl<T: ?Sized> *mut T {
/// ## Examples
///
/// ```
/// #![feature(ptr_mask, strict_provenance)]
/// #![feature(ptr_mask)]
/// let mut v = 17_u32;
/// let ptr: *mut u32 = &mut v;
///
@ -777,7 +768,7 @@ impl<T: ?Sized> *mut T {
/// * `self` and `origin` must either
///
/// * point to the same address, or
/// * both be *derived from* a pointer to the same [allocated object], and the memory range between
/// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocated object], and the memory range between
/// the two pointers must be in bounds of that object. (See below for an example.)
///
/// * The distance between the pointers, in bytes, must be an exact multiple
@ -954,7 +945,7 @@ impl<T: ?Sized> *mut T {
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
@ -1061,7 +1052,7 @@ impl<T: ?Sized> *mut T {
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
/// "wrapping around"), must fit in an `isize`.
///
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.

View File

@ -283,40 +283,39 @@ impl<T: ?Sized> NonNull<T> {
///
/// For more details see the equivalent method on a raw pointer, [`pointer::addr`].
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [`ptr` module documentation][crate::ptr].
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn addr(self) -> NonZero<usize> {
// SAFETY: The pointer is guaranteed by the type to be non-null,
// meaning that the address will be non-zero.
unsafe { NonZero::new_unchecked(self.pointer.addr()) }
}
/// Creates a new pointer with the given address.
/// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of
/// `self`.
///
/// For more details see the equivalent method on a raw pointer, [`pointer::with_addr`].
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [`ptr` module documentation][crate::ptr].
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn with_addr(self, addr: NonZero<usize>) -> Self {
// SAFETY: The result of `ptr::from::with_addr` is non-null because `addr` is guaranteed to be non-zero.
unsafe { NonNull::new_unchecked(self.pointer.with_addr(addr.get()) as *mut _) }
}
/// Creates a new pointer by mapping `self`'s address to a new one.
/// Creates a new pointer by mapping `self`'s address to a new one, preserving the
/// [provenance][crate::ptr#provenance] of `self`.
///
/// For more details see the equivalent method on a raw pointer, [`pointer::map_addr`].
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// see the [`ptr` module documentation][crate::ptr].
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub fn map_addr(self, f: impl FnOnce(NonZero<usize>) -> NonZero<usize>) -> Self {
self.with_addr(f(self.addr()))
}
@ -749,7 +748,6 @@ impl<T: ?Sized> NonNull<T> {
/// *Incorrect* usage:
///
/// ```rust,no_run
/// #![feature(strict_provenance)]
/// use std::ptr::NonNull;
///
/// let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap();

View File

@ -1758,7 +1758,7 @@ impl<T> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
/// #![feature(strict_provenance_atomic_ptr)]
/// use core::sync::atomic::{AtomicPtr, Ordering};
///
/// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
@ -1838,7 +1838,7 @@ impl<T> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
/// #![feature(strict_provenance_atomic_ptr)]
/// use core::sync::atomic::{AtomicPtr, Ordering};
///
/// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
@ -1874,7 +1874,7 @@ impl<T> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
/// #![feature(strict_provenance_atomic_ptr)]
/// use core::sync::atomic::{AtomicPtr, Ordering};
///
/// let atom = AtomicPtr::<i64>::new(core::ptr::without_provenance_mut(1));
@ -1919,7 +1919,7 @@ impl<T> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
/// #![feature(strict_provenance_atomic_ptr)]
/// use core::sync::atomic::{AtomicPtr, Ordering};
///
/// let pointer = &mut 3i64 as *mut i64;
@ -1970,7 +1970,7 @@ impl<T> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
/// #![feature(strict_provenance_atomic_ptr)]
/// use core::sync::atomic::{AtomicPtr, Ordering};
///
/// let pointer = &mut 3i64 as *mut i64;
@ -2020,7 +2020,7 @@ impl<T> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
/// #![feature(strict_provenance_atomic_ptr)]
/// use core::sync::atomic::{AtomicPtr, Ordering};
///
/// let pointer = &mut 3i64 as *mut i64;

View File

@ -1,4 +1,6 @@
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(strict_provenance))]
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_match))]
#![feature(alloc_layout_extra)]
@ -85,7 +87,6 @@
#![feature(std_internals)]
#![feature(step_trait)]
#![feature(str_internals)]
#![feature(strict_provenance)]
#![feature(strict_provenance_atomic_ptr)]
#![feature(test)]
#![feature(trait_upcasting)]

View File

@ -19,8 +19,6 @@
#![feature(panic_unwind)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(strict_provenance)]
#![feature(exposed_provenance)]
#![feature(rustc_attrs)]
#![panic_runtime]
#![feature(panic_runtime)]

View File

@ -9,7 +9,6 @@
repr_simd,
simd_ffi,
staged_api,
strict_provenance,
prelude_import,
ptr_metadata
)]

View File

@ -1,4 +1,4 @@
#![feature(portable_simd, strict_provenance, exposed_provenance)]
#![feature(portable_simd)]
use core_simd::simd::{
ptr::{SimdConstPtr, SimdMutPtr},

View File

@ -32,7 +32,6 @@
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
#![feature(strict_provenance)]
#![recursion_limit = "256"]
#![allow(internal_features)]
#![deny(ffi_unwind_calls)]

View File

@ -279,6 +279,8 @@
//
// Language features:
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(strict_provenance))]
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
#![feature(alloc_error_handler)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
@ -336,7 +338,6 @@
#![feature(error_iter)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_wrapper)]
#![feature(exposed_provenance)]
#![feature(extend_one)]
#![feature(float_gamma)]
#![feature(float_minimum_maximum)]
@ -362,7 +363,6 @@
#![feature(slice_range)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(strict_provenance)]
#![feature(strict_provenance_atomic_ptr)]
#![feature(ub_checks)]
// tidy-alphabetical-end

View File

@ -2,7 +2,6 @@
#![unstable(feature = "panic_unwind", issue = "32837")]
#![feature(link_cfg)]
#![feature(staged_api)]
#![feature(strict_provenance)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
#![cfg_attr(
all(target_family = "wasm", not(target_os = "emscripten")),

View File

@ -1,18 +1,17 @@
# `strict_provenance`
# `strict_provenance_lints`
The tracking issue for this feature is: [#95228]
[#95228]: https://github.com/rust-lang/rust/issues/95228
-----
The `strict_provenance` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints.
The `strict_provenance_lints` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints.
These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model.
The same feature gate is also used for the experimental strict provenance API in `std` (actually `core`).
## Example
```rust
#![feature(strict_provenance)]
#![feature(strict_provenance_lints)]
#![warn(fuzzy_provenance_casts)]
fn main() {

View File

@ -100,6 +100,7 @@ fn main() {
links_ignored_external: 0,
links_ignored_exception: 0,
intra_doc_exceptions: 0,
has_broken_urls: false,
};
checker.walk(&docs, &mut report);
report.report();
@ -116,6 +117,8 @@ struct Checker {
struct Report {
errors: u32,
// Used to provide help message to remind the user to register a page in `SUMMARY.md`.
has_broken_urls: bool,
start: Instant,
html_files: u32,
html_redirects: u32,
@ -274,6 +277,7 @@ impl Checker {
report.links_ignored_exception += 1;
} else {
report.errors += 1;
report.has_broken_urls = true;
println!("{}:{}: broken link - `{}`", pretty_path, i, target_pretty_path);
}
return;
@ -438,6 +442,13 @@ impl Report {
println!("number of links ignored due to exceptions: {}", self.links_ignored_exception);
println!("number of intra doc links ignored: {}", self.intra_doc_exceptions);
println!("errors found: {}", self.errors);
if self.has_broken_urls {
eprintln!(
"NOTE: if you are adding or renaming a markdown file in a mdBook, don't forget to \
register the page in SUMMARY.md"
);
}
}
}

View File

@ -11,8 +11,6 @@
#![feature(let_chains)]
#![feature(trait_upcasting)]
#![feature(strict_overflow_ops)]
#![feature(strict_provenance)]
#![feature(exposed_provenance)]
#![feature(pointer_is_aligned_to)]
#![feature(unqualified_local_imports)]
// Configure clippy and other lints

View File

@ -1,4 +1,3 @@
#![feature(strict_provenance)]
use std::ptr;
fn direct_raw(x: *const (i32, i32)) -> *const i32 {

View File

@ -1,6 +1,5 @@
// Should be caught even without retagging
//@compile-flags: -Zmiri-disable-stacked-borrows
#![feature(strict_provenance)]
use std::ptr::{self, addr_of_mut};
// Deref'ing a dangling raw pointer is fine, but for a dangling box it is not.

View File

@ -1,6 +1,5 @@
// Should be caught even without retagging
//@compile-flags: -Zmiri-disable-stacked-borrows
#![feature(strict_provenance)]
use std::ptr::{self, addr_of_mut};
// Deref'ing a dangling raw pointer is fine, but for a dangling reference it is not.

View File

@ -1,4 +1,3 @@
#![feature(strict_provenance)]
use core::ptr;
fn main() {

View File

@ -1,4 +1,3 @@
#![feature(strict_provenance)]
use std::mem;
#[repr(C, usize)]

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
use std::mem;

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance, exposed_provenance)]
fn main() {
let x: i32 = 3;

View File

@ -1,4 +1,3 @@
#![feature(strict_provenance, exposed_provenance)]
// Ensure that a `ptr::without_provenance` ptr is truly invalid.
fn main() {

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-strict-provenance
#![feature(strict_provenance)]
fn main() {
let x = 22;

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-strict-provenance
#![feature(exposed_provenance)]
fn main() {
let addr = &0 as *const i32 as usize;

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(exposed_provenance)]
// If we have only exposed read-only pointers, doing a write through a wildcard ptr should fail.

View File

@ -1,6 +1,5 @@
//@compile-flags: -Zmiri-symbolic-alignment-check
//@revisions: call_unaligned_ptr read_unaligned_ptr
#![feature(strict_provenance)]
#[path = "../../utils/mod.rs"]
mod utils;

View File

@ -1,7 +1,6 @@
//@compile-flags: -Zmiri-disable-validation
//@error-in-other-file: memory is uninitialized at [0x4..0x8]
//@normalize-stderr-test: "a[0-9]+" -> "ALLOC"
#![feature(strict_provenance)]
#![allow(dropping_copy_types)]
// Test printing allocations that contain single-byte provenance.

View File

@ -3,7 +3,6 @@
//@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
#![feature(io_error_more)]
#![feature(pointer_is_aligned_to)]
#![feature(strict_provenance)]
use std::mem::{size_of, size_of_val};

View File

@ -1,6 +1,5 @@
//@only-target: linux
#![feature(strict_provenance)]
use std::convert::TryInto;
fn main() {

View File

@ -1,4 +1,4 @@
#![feature(strict_provenance, pointer_is_aligned_to)]
#![feature(pointer_is_aligned_to)]
use std::{mem, ptr, slice};
fn test_memcpy() {

View File

@ -2,7 +2,6 @@
//@compile-flags: -Zmiri-disable-isolation
#![feature(io_error_more)]
#![feature(pointer_is_aligned_to)]
#![feature(strict_provenance)]
use std::mem::transmute;

View File

@ -1,6 +1,5 @@
//@ignore-target: windows # No mmap on Windows
//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance
#![feature(strict_provenance)]
use std::io::Error;
use std::{ptr, slice};

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-symbolic-alignment-check
#![feature(strict_provenance)]
use std::mem;

View File

@ -2,7 +2,7 @@
//@[tree]compile-flags: -Zmiri-tree-borrows
//@compile-flags: -Zmiri-strict-provenance
#![feature(strict_provenance, strict_provenance_atomic_ptr)]
#![feature(strict_provenance_atomic_ptr)]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]

View File

@ -5,7 +5,6 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(allocator_api)]
#![feature(strict_provenance)]
use std::alloc::{AllocError, Allocator, Layout};
use std::cell::{Cell, UnsafeCell};

View File

@ -1,7 +1,6 @@
//! Regression test for <https://github.com/rust-lang/miri/issues/3450>:
//! When the address gets reused, there should be a happens-before relation.
//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=1.0
#![feature(strict_provenance)]
#![feature(sync_unsafe_cell)]
use std::cell::SyncUnsafeCell;

View File

@ -7,7 +7,6 @@
// MIR inlining will put every evaluation of the const we're repeatedly evaluating into the same
// stack frame, breaking this test.
//@compile-flags: -Zinline-mir=no
#![feature(strict_provenance)]
const EVALS: usize = 256;

View File

@ -1,4 +1,4 @@
#![feature(custom_mir, core_intrinsics, strict_provenance)]
#![feature(custom_mir, core_intrinsics)]
use std::intrinsics::mir::*;
// The `Drop` terminator on a type with no drop glue should be a NOP.

View File

@ -1,6 +1,6 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(extern_types, strict_provenance)]
#![feature(extern_types)]
use std::ptr;

View File

@ -1,6 +1,5 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(strict_provenance)]
use std::{mem, ptr};
const PTR_SIZE: usize = mem::size_of::<&i32>();

View File

@ -2,7 +2,6 @@
// Tree Borrows doesn't support int2ptr casts, but let's make sure we don't immediately crash either.
//@[tree]compile-flags: -Zmiri-tree-borrows
//@[stack]compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance, exposed_provenance)]
use std::ptr;

View File

@ -1,4 +1,3 @@
#![feature(strict_provenance)]
use std::mem;
use std::ptr::{self, addr_of};

View File

@ -1,5 +1,4 @@
#![feature(ptr_mask)]
#![feature(strict_provenance)]
fn main() {
let v: u32 = 0xABCDABCD;

View File

@ -4,7 +4,6 @@
#![feature(slice_as_chunks)]
#![feature(slice_partition_dedup)]
#![feature(layout_for_ptr)]
#![feature(strict_provenance)]
use std::{ptr, slice};

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(exposed_provenance)]
use std::ptr;
// Just to make sure that casting a ref to raw, to int and back to raw

View File

@ -2,7 +2,6 @@
// printing, not how it interacts with the GC.
//@compile-flags: -Zmiri-permissive-provenance -Zmiri-provenance-gc=0
#![feature(strict_provenance)]
use std::alloc::{self, Layout};
use std::mem::ManuallyDrop;

View File

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(exposed_provenance)]
use std::ptr;

View File

@ -1,6 +1,5 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(strict_provenance)]
use std::{mem, ptr};
fn t1() {

View File

@ -1,5 +1,4 @@
// Various tests ensuring that underscore patterns really just construct the place, but don't check its contents.
#![feature(strict_provenance)]
#![feature(never_type)]
use std::ptr;

View File

@ -1,5 +1,4 @@
//! Tests specific for <https://github.com/rust-lang/rust/issues/117945>: zero-sized operations.
#![feature(strict_provenance)]
use std::ptr;

View File

@ -6,7 +6,6 @@
//@ compile-flags: -O -Cno-prepopulate-passes
#![crate_type = "lib"]
#![feature(strict_provenance)]
#![feature(strict_provenance_atomic_ptr)]
use std::ptr::without_provenance_mut;

View File

@ -1,7 +1,6 @@
//@ compile-flags: -O -C debug-assertions=yes
#![crate_type = "lib"]
#![feature(strict_provenance)]
#[no_mangle]
pub fn test(src: *const u8, dst: *const u8) -> usize {

View File

@ -5,8 +5,6 @@
// Regression for <https://github.com/rust-lang/rust/issues/127089>
#![feature(strict_provenance)]
struct Foo<T>(std::marker::PhantomData<T>);
impl<T> Foo<T> {

View File

@ -31,6 +31,10 @@ fn main() {
"rustc_pattern_analysis",
"-p",
"rustc_lexer",
"-p",
"rustc_abi",
"-p",
"rustc_parse_format",
])
.run();
}

View File

@ -2,8 +2,6 @@
//@ compile-flags: -Copt-level=2
//@ run-pass
#![feature(exposed_provenance)]
use std::ptr;
fn main() {

View File

@ -4,8 +4,6 @@
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908
#![feature(exposed_provenance)]
use std::ptr;
fn f() -> usize {

View File

@ -4,8 +4,6 @@
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
#![feature(exposed_provenance)]
use std::ptr;
#[inline(never)]

View File

@ -4,8 +4,6 @@
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
#![feature(exposed_provenance)]
use std::ptr;
#[inline(never)]

View File

@ -4,8 +4,6 @@
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
#![feature(exposed_provenance)]
use std::ptr;
fn main() {

View File

@ -4,8 +4,6 @@
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
#![feature(exposed_provenance)]
use std::ptr;
fn main() {

View File

@ -4,8 +4,6 @@
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
#![feature(exposed_provenance)]
use std::{
cell::{Ref, RefCell},
ptr,

View File

@ -4,8 +4,6 @@
// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
#![feature(exposed_provenance)]
use std::ptr;
fn main() {

View File

@ -2,8 +2,6 @@
//@ compile-flags: -Copt-level=2
//@ run-pass
#![feature(strict_provenance)]
use std::ptr;
fn main() {

View File

@ -4,8 +4,6 @@
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908
#![feature(strict_provenance)]
use std::ptr;
fn f() -> usize {

View File

@ -4,8 +4,6 @@
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
#![feature(strict_provenance)]
use std::ptr;
#[inline(never)]

View File

@ -4,8 +4,6 @@
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
#![feature(strict_provenance)]
use std::ptr;
#[inline(never)]

View File

@ -4,8 +4,6 @@
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
#![feature(strict_provenance)]
use std::ptr;
fn main() {

View File

@ -4,8 +4,6 @@
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
#![feature(strict_provenance)]
use std::ptr;
fn main() {

View File

@ -4,8 +4,6 @@
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
#![feature(strict_provenance)]
use std::{
cell::{Ref, RefCell},
ptr,

View File

@ -4,8 +4,6 @@
// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
#![feature(strict_provenance)]
use std::ptr;
fn main() {

View File

@ -1,24 +1,24 @@
warning: unknown lint: `fuzzy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:3:1
--> $DIR/feature-gate-strict_provenance_lints.rs:3:1
|
LL | #![deny(fuzzy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `fuzzy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
= note: see issue #130351 <https://github.com/rust-lang/rust/issues/130351> for more information
= help: add `#![feature(strict_provenance_lints)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: `#[warn(unknown_lints)]` on by default
warning: unknown lint: `lossy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:5:1
--> $DIR/feature-gate-strict_provenance_lints.rs:5:1
|
LL | #![deny(lossy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `lossy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
= note: see issue #130351 <https://github.com/rust-lang/rust/issues/130351> for more information
= help: add `#![feature(strict_provenance_lints)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
warning: 2 warnings emitted

View File

@ -1,4 +1,4 @@
#![feature(strict_provenance)]
#![feature(strict_provenance_lints)]
#![deny(fuzzy_provenance_casts)]
fn main() {

View File

@ -1,4 +1,4 @@
#![feature(strict_provenance)]
#![feature(strict_provenance_lints)]
#![deny(lossy_provenance_casts)]
fn main() {

View File

@ -0,0 +1,40 @@
error: binding has unit type `()`
--> $DIR/unit_bindings.rs:50:5
|
LL | let _ = expr;
| ^^^^-^^^^^^^^
| |
| this pattern is inferred to be the unit type `()`
|
note: the lint level is defined here
--> $DIR/unit_bindings.rs:22:30
|
LL | #![cfg_attr(deny_level, deny(unit_bindings))]
| ^^^^^^^^^^^^^
error: binding has unit type `()`
--> $DIR/unit_bindings.rs:51:5
|
LL | let pat = expr;
| ^^^^---^^^^^^^^
| |
| this pattern is inferred to be the unit type `()`
error: binding has unit type `()`
--> $DIR/unit_bindings.rs:52:5
|
LL | let _pat = expr;
| ^^^^----^^^^^^^^
| |
| this pattern is inferred to be the unit type `()`
error: binding has unit type `()`
--> $DIR/unit_bindings.rs:55:5
|
LL | let list = v.sort();
| ^^^^----^^^^^^^^^^^^
| |
| this pattern is inferred to be the unit type `()`
error: aborting due to 4 previous errors

View File

@ -0,0 +1,60 @@
//! Basic checks for `unit_bindings` lint.
//!
//! The `unit_bindings` lint tries to detect cases like `let list = list.sort()`. The lint will
//! trigger on bindings that have the unit `()` type **except** if:
//!
//! - The user wrote `()` on either side, i.e.
//! - `let () = <expr>;` or `let <expr> = ();`
//! - `let _ = ();`
//! - The binding occurs within macro expansions, e.g. `foo!();`.
//! - The user explicitly provided type annotations, e.g. `let x: () = <expr>`.
//!
//! Examples where the lint *should* fire on include:
//!
//! - `let _ = <expr>;`
//! - `let pat = <expr>;`
//! - `let _pat = <expr>;`
//@ revisions: default_level deny_level
//@[default_level] check-pass (`unit_bindings` is currently allow-by-default)
#![allow(unused)]
#![cfg_attr(deny_level, deny(unit_bindings))]
// The `list` binding below should trigger the lint if it's not contained in a macro expansion.
macro_rules! expands_to_sus {
() => {
let mut v = [1, 2, 3];
let list = v.sort();
}
}
// No warning for `y` and `z` because it is provided as type parameter.
fn ty_param_check<T: Copy>(x: T) {
let y = x;
let z: T = x;
}
fn main() {
// No warning if user explicitly wrote `()` on either side.
let expr = ();
let () = expr;
let _ = ();
// No warning if user explicitly annotates the unit type on the binding.
let pat: () = expr;
// No warning for let bindings with unit type in macro expansions.
expands_to_sus!();
// No warning for unit bindings in generic fns.
ty_param_check(());
let _ = expr; //[deny_level]~ ERROR binding has unit type
let pat = expr; //[deny_level]~ ERROR binding has unit type
let _pat = expr; //[deny_level]~ ERROR binding has unit type
let mut v = [1, 2, 3];
let list = v.sort(); //[deny_level]~ ERROR binding has unit type
// Limitation: the lint currently does not fire on nested unit LHS bindings, i.e.
// this will not currently trigger the lint.
let (nested, _) = (expr, 0i32);
}

View File

@ -7,8 +7,6 @@
// that will fail on dereferencing of a pointer to u64 which is not 8-byte-aligned but is
// 4-byte-aligned.
#![feature(strict_provenance)]
fn main() {
let mut x = [0u64; 2];
let ptr = x.as_mut_ptr();

View File

@ -1,8 +1,6 @@
//@ run-pass
//@ compile-flags: -C debug-assertions
#![feature(strict_provenance)]
#[repr(packed)]
struct Misaligner {
_head: u8,

View File

@ -5,7 +5,6 @@
#![allow(dead_code)]
#![feature(never_type)]
#![feature(pointer_is_aligned_to)]
#![feature(strict_provenance)]
use std::mem::size_of;
use std::num::NonZero;

Some files were not shown because too many files have changed in this diff Show More