Auto merge of #81545 - JohnTitor:rollup-zlt3tn6, r=JohnTitor
Rollup of 16 pull requests Successful merges: - #79023 (Add `core::stream::Stream`) - #80562 (Consider Scalar to be a bool only if its unsigned) - #80886 (Stabilize raw ref macros) - #80959 (Stabilize `unsigned_abs`) - #81291 (Support FRU pattern with `[feature(capture_disjoint_fields)]`) - #81409 (Slight simplification of chars().count()) - #81468 (cfg(version): treat nightlies as complete) - #81473 (Warn write-only fields) - #81495 (rustdoc: Remove unnecessary optional) - #81499 (Updated Vec::splice documentation) - #81501 (update rustfmt to v1.4.34) - #81505 (`fn cold_path` doesn't need to be pub) - #81512 (Add missing variants in match binding) - #81515 (Fix typo in pat.rs) - #81519 (Don't print error output from rustup when detecting default build triple) - #81520 (Don't clone LLVM submodule when download-ci-llvm is set) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7ce1b3b244
@ -4442,7 +4442,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "1.4.32"
|
||||
version = "1.4.34"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.6.1",
|
||||
"anyhow",
|
||||
|
@ -32,7 +32,7 @@ use std::slice;
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
|
||||
fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
|
||||
f()
|
||||
}
|
||||
|
||||
|
@ -586,12 +586,14 @@ pub fn eval_condition(
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let channel = env!("CFG_RELEASE_CHANNEL");
|
||||
let nightly = channel == "nightly" || channel == "dev";
|
||||
let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
|
||||
|
||||
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-625474439 for details
|
||||
if nightly { rustc_version > min_version } else { rustc_version >= min_version }
|
||||
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
|
||||
if sess.assume_incomplete_release {
|
||||
rustc_version > min_version
|
||||
} else {
|
||||
rustc_version >= min_version
|
||||
}
|
||||
}
|
||||
ast::MetaItemKind::List(ref mis) => {
|
||||
for mi in mis.iter() {
|
||||
|
@ -540,6 +540,7 @@ fn test_debugging_options_tracking_hash() {
|
||||
// This list is in alphabetical order.
|
||||
tracked!(allow_features, Some(vec![String::from("lang_items")]));
|
||||
tracked!(always_encode_mir, true);
|
||||
tracked!(assume_incomplete_release, true);
|
||||
tracked!(asm_comments, true);
|
||||
tracked!(binary_dep_depinfo, true);
|
||||
tracked!(chalk, true);
|
||||
|
@ -588,12 +588,3 @@ pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, i
|
||||
debug_assert!(source.len() == 0); // We should have consumed the source buffer.
|
||||
uint
|
||||
}
|
||||
|
||||
/// Computes the unsigned absolute value without wrapping or panicking.
|
||||
#[inline]
|
||||
pub fn uabs(value: i64) -> u64 {
|
||||
// The only tricky part here is if value == i64::MIN. In that case,
|
||||
// wrapping_abs() returns i64::MIN == -2^63. Casting this value to a u64
|
||||
// gives 2^63, the correct value.
|
||||
value.wrapping_abs() as u64
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{uabs, AllocId, InterpResult};
|
||||
use super::{AllocId, InterpResult};
|
||||
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_target::abi::{HasDataLayout, Size};
|
||||
@ -57,7 +57,7 @@ pub trait PointerArithmetic: HasDataLayout {
|
||||
#[inline]
|
||||
fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
|
||||
// We need to make sure that i fits in a machine isize.
|
||||
let n = uabs(i);
|
||||
let n = i.unsigned_abs();
|
||||
if i >= 0 {
|
||||
let (val, over) = self.overflowing_offset(val, n);
|
||||
(val, over || i > self.machine_isize_max())
|
||||
|
@ -7,7 +7,7 @@ use std::convert::TryFrom;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::{
|
||||
self,
|
||||
interpret::{uabs, ConstValue, GlobalId, InterpResult, Scalar},
|
||||
interpret::{ConstValue, GlobalId, InterpResult, Scalar},
|
||||
BinOp,
|
||||
};
|
||||
use rustc_middle::ty;
|
||||
@ -542,7 +542,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// memory between these pointers must be accessible. Note that we do not require the
|
||||
// pointers to be properly aligned (unlike a read/write operation).
|
||||
let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
|
||||
let size: u64 = uabs(offset_bytes);
|
||||
let size = offset_bytes.unsigned_abs();
|
||||
// This call handles checking for integer/NULL pointers.
|
||||
self.memory.check_ptr_access_align(
|
||||
min_ptr,
|
||||
|
@ -303,7 +303,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
|
||||
self.base
|
||||
}
|
||||
|
||||
fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
|
||||
crate fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
|
||||
self.project(PlaceElem::Field(f, ty))
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let field_names = this.hir.all_fields(adt_def, variant_index);
|
||||
|
||||
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
|
||||
let base = unpack!(block = this.as_place(block, base));
|
||||
let place_builder = unpack!(block = this.as_place_builder(block, base));
|
||||
|
||||
// MIR does not natively support FRU, so for each
|
||||
// base-supplied field, generate an operand that
|
||||
@ -306,9 +306,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
.zip(field_types.into_iter())
|
||||
.map(|(n, ty)| match fields_map.get(&n) {
|
||||
Some(v) => v.clone(),
|
||||
None => this.consume_by_copy_or_move(
|
||||
this.hir.tcx().mk_place_field(base, n, ty),
|
||||
),
|
||||
None => {
|
||||
let place_builder = place_builder.clone();
|
||||
this.consume_by_copy_or_move(
|
||||
place_builder
|
||||
.field(n, ty)
|
||||
.into_place(this.hir.tcx(), this.hir.typeck_results()),
|
||||
)
|
||||
},
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
|
@ -240,7 +240,7 @@ impl<'a> Parser<'a> {
|
||||
Err(err)
|
||||
}
|
||||
|
||||
/// Parse and throw away a parentesized comma separated
|
||||
/// Parse and throw away a parenthesized comma separated
|
||||
/// sequence of patterns until `)` is reached.
|
||||
fn skip_pat_list(&mut self) -> PResult<'a, ()> {
|
||||
while !self.check(&token::CloseDelim(token::Paren)) {
|
||||
|
@ -37,6 +37,15 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
|
||||
)
|
||||
}
|
||||
|
||||
fn base_expr<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
|
||||
loop {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Field(base, ..) => expr = base,
|
||||
_ => return expr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MarkSymbolVisitor<'tcx> {
|
||||
worklist: Vec<hir::HirId>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -263,6 +272,12 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
||||
hir::ExprKind::MethodCall(..) => {
|
||||
self.lookup_and_handle_method(expr.hir_id);
|
||||
}
|
||||
hir::ExprKind::Assign(ref left, ref right, ..) => {
|
||||
// Ignore write to field
|
||||
self.visit_expr(base_expr(left));
|
||||
self.visit_expr(right);
|
||||
return;
|
||||
}
|
||||
hir::ExprKind::Field(ref lhs, ..) => {
|
||||
self.handle_field_access(&lhs, expr.hir_id);
|
||||
}
|
||||
|
@ -977,7 +977,7 @@ impl<'a> Resolver<'a> {
|
||||
});
|
||||
if let Some(def_span) = def_span {
|
||||
if span.overlaps(def_span) {
|
||||
// Don't suggest typo suggestion for itself like in the followoing:
|
||||
// Don't suggest typo suggestion for itself like in the following:
|
||||
// error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
|
||||
// --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
|
||||
// |
|
||||
|
@ -854,6 +854,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"only allow the listed language features to be enabled in code (space separated)"),
|
||||
always_encode_mir: bool = (false, parse_bool, [TRACKED],
|
||||
"encode MIR of all functions into the crate metadata (default: no)"),
|
||||
assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
|
||||
"make cfg(version) treat the current version as incomplete (default: no)"),
|
||||
asm_comments: bool = (false, parse_bool, [TRACKED],
|
||||
"generate comments into the assembly (may change behavior) (default: no)"),
|
||||
ast_json: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
@ -138,6 +138,8 @@ pub struct ParseSess {
|
||||
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
|
||||
/// All the type ascriptions expressions that have had a suggestion for likely path typo.
|
||||
pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
|
||||
/// Whether cfg(version) should treat the current release as incomplete
|
||||
pub assume_incomplete_release: bool,
|
||||
}
|
||||
|
||||
impl ParseSess {
|
||||
@ -164,6 +166,7 @@ impl ParseSess {
|
||||
reached_eof: Lock::new(false),
|
||||
env_depinfo: Default::default(),
|
||||
type_ascription_path_suggestions: Default::default(),
|
||||
assume_incomplete_release: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1344,7 +1344,8 @@ pub fn build_session(
|
||||
None
|
||||
};
|
||||
|
||||
let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map);
|
||||
let mut parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map);
|
||||
parse_sess.assume_incomplete_release = sopts.debugging_opts.assume_incomplete_release;
|
||||
let sysroot = match &sopts.maybe_sysroot {
|
||||
Some(sysroot) => sysroot.clone(),
|
||||
None => filesearch::get_or_default_sysroot(),
|
||||
|
@ -530,7 +530,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
|
||||
if val < 0 {
|
||||
neg = true;
|
||||
}
|
||||
Some(val.wrapping_abs() as u128)
|
||||
Some(val.unsigned_abs())
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
|
@ -103,7 +103,12 @@ impl ArgAttributes {
|
||||
}
|
||||
|
||||
pub fn ext(&mut self, ext: ArgExtension) -> &mut Self {
|
||||
assert!(self.arg_ext == ArgExtension::None || self.arg_ext == ext);
|
||||
assert!(
|
||||
self.arg_ext == ArgExtension::None || self.arg_ext == ext,
|
||||
"cannot set {:?} when {:?} is already set",
|
||||
ext,
|
||||
self.arg_ext
|
||||
);
|
||||
self.arg_ext = ext;
|
||||
self
|
||||
}
|
||||
|
@ -682,7 +682,7 @@ pub struct Scalar {
|
||||
|
||||
impl Scalar {
|
||||
pub fn is_bool(&self) -> bool {
|
||||
if let Int(I8, _) = self.value { self.valid_range == (0..=1) } else { false }
|
||||
matches!(self.value, Int(I8, false)) && self.valid_range == (0..=1)
|
||||
}
|
||||
|
||||
/// Returns the valid range as a `x..y` range.
|
||||
|
@ -149,6 +149,7 @@ use core::ops::{
|
||||
};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, Unique};
|
||||
use core::stream::Stream;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use crate::alloc::{handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw};
|
||||
@ -1621,3 +1622,16 @@ where
|
||||
F::poll(Pin::new(&mut *self), cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_stream", issue = "79024")]
|
||||
impl<S: ?Sized + Stream + Unpin> Stream for Box<S> {
|
||||
type Item = S::Item;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Pin::new(&mut **self).poll_next(cx)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(**self).size_hint()
|
||||
}
|
||||
}
|
||||
|
@ -545,8 +545,8 @@ impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
|
||||
// to avoid aliasing with outstanding references to other elements,
|
||||
// in particular, those returned to the caller in earlier iterations.
|
||||
let leaf = Self::as_leaf_ptr(&mut self);
|
||||
let keys = unsafe { &raw const (*leaf).keys };
|
||||
let vals = unsafe { &raw mut (*leaf).vals };
|
||||
let keys = unsafe { ptr::addr_of!((*leaf).keys) };
|
||||
let vals = unsafe { ptr::addr_of_mut!((*leaf).vals) };
|
||||
// We must coerce to unsized array pointers because of Rust issue #74679.
|
||||
let keys: *const [_] = keys;
|
||||
let vals: *mut [_] = vals;
|
||||
|
@ -82,6 +82,7 @@
|
||||
#![feature(array_windows)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(async_stream)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(cfg_sanitize)]
|
||||
@ -115,7 +116,6 @@
|
||||
#![feature(pattern)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(range_bounds_assert_len)]
|
||||
#![feature(raw_ref_op)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(receiver_trait)]
|
||||
#![cfg_attr(bootstrap, feature(min_const_generics))]
|
||||
|
@ -398,7 +398,7 @@ impl<T> Rc<T> {
|
||||
|
||||
unsafe {
|
||||
let inner = init_ptr.as_ptr();
|
||||
ptr::write(&raw mut (*inner).value, data);
|
||||
ptr::write(ptr::addr_of_mut!((*inner).value), data);
|
||||
|
||||
let prev_value = (*inner).strong.get();
|
||||
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
|
||||
@ -804,7 +804,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
// SAFETY: This cannot go through Deref::deref or Rc::inner because
|
||||
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
|
||||
// write through the pointer after the Rc is recovered through `from_raw`.
|
||||
unsafe { &raw const (*ptr).value }
|
||||
unsafe { ptr::addr_of_mut!((*ptr).value) }
|
||||
}
|
||||
|
||||
/// Constructs an `Rc<T>` from a raw pointer.
|
||||
@ -1917,7 +1917,7 @@ impl<T: ?Sized> Weak<T> {
|
||||
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
||||
// The payload may be dropped at this point, and we have to maintain provenance,
|
||||
// so use raw pointer manipulation.
|
||||
unsafe { &raw const (*ptr).value }
|
||||
unsafe { ptr::addr_of_mut!((*ptr).value) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,7 +384,7 @@ impl<T> Arc<T> {
|
||||
// reference into a strong reference.
|
||||
unsafe {
|
||||
let inner = init_ptr.as_ptr();
|
||||
ptr::write(&raw mut (*inner).data, data);
|
||||
ptr::write(ptr::addr_of_mut!((*inner).data), data);
|
||||
|
||||
// The above write to the data field must be visible to any threads which
|
||||
// observe a non-zero strong count. Therefore we need at least "Release" ordering
|
||||
@ -800,7 +800,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
// SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because
|
||||
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
|
||||
// write through the pointer after the Rc is recovered through `from_raw`.
|
||||
unsafe { &raw const (*ptr).data }
|
||||
unsafe { ptr::addr_of_mut!((*ptr).data) }
|
||||
}
|
||||
|
||||
/// Constructs an `Arc<T>` from a raw pointer.
|
||||
@ -1677,7 +1677,7 @@ impl<T: ?Sized> Weak<T> {
|
||||
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
||||
// The payload may be dropped at this point, and we have to maintain provenance,
|
||||
// so use raw pointer manipulation.
|
||||
unsafe { &raw mut (*ptr).data }
|
||||
unsafe { ptr::addr_of_mut!((*ptr).data) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2211,7 +2211,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// This is optimal if:
|
||||
///
|
||||
/// * The tail (elements in the vector after `range`) is empty,
|
||||
/// * or `replace_with` yields fewer elements than `range`’s length
|
||||
/// * or `replace_with` yields fewer or equal elements than `range`’s length
|
||||
/// * or the lower bound of its `size_hint()` is exact.
|
||||
///
|
||||
/// Otherwise, a temporary vector is allocated and the tail is moved twice.
|
||||
|
@ -126,7 +126,6 @@
|
||||
#![feature(auto_traits)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(prelude_import)]
|
||||
#![feature(raw_ref_macros)]
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(simd_ffi)]
|
||||
@ -254,6 +253,8 @@ pub mod panicking;
|
||||
pub mod pin;
|
||||
pub mod raw;
|
||||
pub mod result;
|
||||
#[unstable(feature = "async_stream", issue = "79024")]
|
||||
pub mod stream;
|
||||
pub mod sync;
|
||||
|
||||
pub mod fmt;
|
||||
|
@ -332,7 +332,7 @@ fn bound_intermediate_digits(decimal: &Decimal<'_>, e: i64) -> u64 {
|
||||
// It tries to find a positive number k such that `f << k / 10^e` is an in-range
|
||||
// significand. This will result in about `2^53 * f * 10^e` < `10^17 * f * 10^e`.
|
||||
// One input that triggers this is 0.33...33 (375 x 3).
|
||||
f_len + (e.abs() as u64) + 17
|
||||
f_len + e.unsigned_abs() + 17
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1158,12 +1158,12 @@ macro_rules! int_impl {
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(unsigned_abs)]
|
||||
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");")]
|
||||
#[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");")]
|
||||
/// assert_eq!((-128i8).unsigned_abs(), 128u8);
|
||||
/// ```
|
||||
#[unstable(feature = "unsigned_abs", issue = "74913")]
|
||||
#[stable(feature = "unsigned_abs", since = "1.51.0")]
|
||||
#[rustc_const_stable(feature = "unsigned_abs", since = "1.51.0")]
|
||||
#[inline]
|
||||
pub const fn unsigned_abs(self) -> $UnsignedT {
|
||||
self.wrapping_abs() as $UnsignedT
|
||||
|
@ -1501,7 +1501,6 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(raw_ref_macros)]
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// #[repr(packed)]
|
||||
@ -1512,14 +1511,14 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
|
||||
///
|
||||
/// let packed = Packed { f1: 1, f2: 2 };
|
||||
/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
|
||||
/// let raw_f2 = ptr::raw_const!(packed.f2);
|
||||
/// let raw_f2 = ptr::addr_of!(packed.f2);
|
||||
/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
|
||||
/// ```
|
||||
#[unstable(feature = "raw_ref_macros", issue = "73394")]
|
||||
#[stable(feature = "raw_ref_macros", since = "1.51.0")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[allow_internal_unstable(raw_ref_op)]
|
||||
pub macro raw_const($e:expr) {
|
||||
&raw const $e
|
||||
pub macro addr_of($place:expr) {
|
||||
&raw const $place
|
||||
}
|
||||
|
||||
/// Create a `mut` raw pointer to a place, without creating an intermediate reference.
|
||||
@ -1534,7 +1533,6 @@ pub macro raw_const($e:expr) {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(raw_ref_macros)]
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// #[repr(packed)]
|
||||
@ -1545,13 +1543,13 @@ pub macro raw_const($e:expr) {
|
||||
///
|
||||
/// let mut packed = Packed { f1: 1, f2: 2 };
|
||||
/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
|
||||
/// let raw_f2 = ptr::raw_mut!(packed.f2);
|
||||
/// let raw_f2 = ptr::addr_of_mut!(packed.f2);
|
||||
/// unsafe { raw_f2.write_unaligned(42); }
|
||||
/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
|
||||
/// ```
|
||||
#[unstable(feature = "raw_ref_macros", issue = "73394")]
|
||||
#[stable(feature = "raw_ref_macros", since = "1.51.0")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[allow_internal_unstable(raw_ref_op)]
|
||||
pub macro raw_mut($e:expr) {
|
||||
&raw mut $e
|
||||
pub macro addr_of_mut($place:expr) {
|
||||
&raw mut $place
|
||||
}
|
||||
|
@ -543,8 +543,8 @@ impl<T> [T] {
|
||||
#[inline]
|
||||
pub fn swap(&mut self, a: usize, b: usize) {
|
||||
// Can't take two mutable loans from one vector, so instead use raw pointers.
|
||||
let pa = ptr::raw_mut!(self[a]);
|
||||
let pb = ptr::raw_mut!(self[b]);
|
||||
let pa = ptr::addr_of_mut!(self[a]);
|
||||
let pb = ptr::addr_of_mut!(self[b]);
|
||||
// SAFETY: `pa` and `pb` have been created from safe mutable references and refer
|
||||
// to elements in the slice and therefore are guaranteed to be valid and aligned.
|
||||
// Note that accessing the elements behind `a` and `b` is checked and will
|
||||
|
@ -47,12 +47,7 @@ impl<'a> Iterator for Chars<'a> {
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
// length in `char` is equal to the number of non-continuation bytes
|
||||
let bytes_len = self.iter.len();
|
||||
let mut cont_bytes = 0;
|
||||
for &byte in self.iter {
|
||||
cont_bytes += utf8_is_cont_byte(byte) as usize;
|
||||
}
|
||||
bytes_len - cont_bytes
|
||||
self.iter.filter(|&&byte| !utf8_is_cont_byte(byte)).count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
127
library/core/src/stream/mod.rs
Normal file
127
library/core/src/stream/mod.rs
Normal file
@ -0,0 +1,127 @@
|
||||
//! Composable asynchronous iteration.
|
||||
//!
|
||||
//! If futures are asynchronous values, then streams are asynchronous
|
||||
//! iterators. If you've found yourself with an asynchronous collection of some kind,
|
||||
//! and needed to perform an operation on the elements of said collection,
|
||||
//! you'll quickly run into 'streams'. Streams are heavily used in idiomatic
|
||||
//! asynchronous Rust code, so it's worth becoming familiar with them.
|
||||
//!
|
||||
//! Before explaining more, let's talk about how this module is structured:
|
||||
//!
|
||||
//! # Organization
|
||||
//!
|
||||
//! This module is largely organized by type:
|
||||
//!
|
||||
//! * [Traits] are the core portion: these traits define what kind of streams
|
||||
//! exist and what you can do with them. The methods of these traits are worth
|
||||
//! putting some extra study time into.
|
||||
//! * Functions provide some helpful ways to create some basic streams.
|
||||
//! * Structs are often the return types of the various methods on this
|
||||
//! module's traits. You'll usually want to look at the method that creates
|
||||
//! the `struct`, rather than the `struct` itself. For more detail about why,
|
||||
//! see '[Implementing Stream](#implementing-stream)'.
|
||||
//!
|
||||
//! [Traits]: #traits
|
||||
//!
|
||||
//! That's it! Let's dig into streams.
|
||||
//!
|
||||
//! # Stream
|
||||
//!
|
||||
//! The heart and soul of this module is the [`Stream`] trait. The core of
|
||||
//! [`Stream`] looks like this:
|
||||
//!
|
||||
//! ```
|
||||
//! # use core::task::{Context, Poll};
|
||||
//! # use core::pin::Pin;
|
||||
//! trait Stream {
|
||||
//! type Item;
|
||||
//! fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Unlike `Iterator`, `Stream` makes a distinction between the [`poll_next`]
|
||||
//! method which is used when implementing a `Stream`, and a (to-be-implemented)
|
||||
//! `next` method which is used when consuming a stream. Consumers of `Stream`
|
||||
//! only need to consider `next`, which when called, returns a future which
|
||||
//! yields `Option<Stream::Item>`.
|
||||
//!
|
||||
//! The future returned by `next` will yield `Some(Item)` as long as there are
|
||||
//! elements, and once they've all been exhausted, will yield `None` to indicate
|
||||
//! that iteration is finished. If we're waiting on something asynchronous to
|
||||
//! resolve, the future will wait until the stream is ready to yield again.
|
||||
//!
|
||||
//! Individual streams may choose to resume iteration, and so calling `next`
|
||||
//! again may or may not eventually yield `Some(Item)` again at some point.
|
||||
//!
|
||||
//! [`Stream`]'s full definition includes a number of other methods as well,
|
||||
//! but they are default methods, built on top of [`poll_next`], and so you get
|
||||
//! them for free.
|
||||
//!
|
||||
//! [`Poll`]: super::task::Poll
|
||||
//! [`poll_next`]: Stream::poll_next
|
||||
//!
|
||||
//! # Implementing Stream
|
||||
//!
|
||||
//! Creating a stream of your own involves two steps: creating a `struct` to
|
||||
//! hold the stream's state, and then implementing [`Stream`] for that
|
||||
//! `struct`.
|
||||
//!
|
||||
//! Let's make a stream named `Counter` which counts from `1` to `5`:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! #![feature(async_stream)]
|
||||
//! # use core::stream::Stream;
|
||||
//! # use core::task::{Context, Poll};
|
||||
//! # use core::pin::Pin;
|
||||
//!
|
||||
//! // First, the struct:
|
||||
//!
|
||||
//! /// A stream which counts from one to five
|
||||
//! struct Counter {
|
||||
//! count: usize,
|
||||
//! }
|
||||
//!
|
||||
//! // we want our count to start at one, so let's add a new() method to help.
|
||||
//! // This isn't strictly necessary, but is convenient. Note that we start
|
||||
//! // `count` at zero, we'll see why in `poll_next()`'s implementation below.
|
||||
//! impl Counter {
|
||||
//! fn new() -> Counter {
|
||||
//! Counter { count: 0 }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // Then, we implement `Stream` for our `Counter`:
|
||||
//!
|
||||
//! impl Stream for Counter {
|
||||
//! // we will be counting with usize
|
||||
//! type Item = usize;
|
||||
//!
|
||||
//! // poll_next() is the only required method
|
||||
//! fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
//! // Increment our count. This is why we started at zero.
|
||||
//! self.count += 1;
|
||||
//!
|
||||
//! // Check to see if we've finished counting or not.
|
||||
//! if self.count < 6 {
|
||||
//! Poll::Ready(Some(self.count))
|
||||
//! } else {
|
||||
//! Poll::Ready(None)
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Laziness
|
||||
//!
|
||||
//! Streams are *lazy*. This means that just creating a stream doesn't _do_ a
|
||||
//! whole lot. Nothing really happens until you call `next`. This is sometimes a
|
||||
//! source of confusion when creating a stream solely for its side effects. The
|
||||
//! compiler will warn us about this kind of behavior:
|
||||
//!
|
||||
//! ```text
|
||||
//! warning: unused result that must be used: streams do nothing unless polled
|
||||
//! ```
|
||||
|
||||
mod stream;
|
||||
|
||||
pub use stream::Stream;
|
110
library/core/src/stream/stream/mod.rs
Normal file
110
library/core/src/stream/stream/mod.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use crate::ops::DerefMut;
|
||||
use crate::pin::Pin;
|
||||
use crate::task::{Context, Poll};
|
||||
|
||||
/// An interface for dealing with asynchronous iterators.
|
||||
///
|
||||
/// This is the main stream trait. For more about the concept of streams
|
||||
/// generally, please see the [module-level documentation]. In particular, you
|
||||
/// may want to know how to [implement `Stream`][impl].
|
||||
///
|
||||
/// [module-level documentation]: index.html
|
||||
/// [impl]: index.html#implementing-stream
|
||||
#[unstable(feature = "async_stream", issue = "79024")]
|
||||
#[must_use = "streams do nothing unless polled"]
|
||||
pub trait Stream {
|
||||
/// The type of items yielded by the stream.
|
||||
type Item;
|
||||
|
||||
/// Attempt to pull out the next value of this stream, registering the
|
||||
/// current task for wakeup if the value is not yet available, and returning
|
||||
/// `None` if the stream is exhausted.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// There are several possible return values, each indicating a distinct
|
||||
/// stream state:
|
||||
///
|
||||
/// - `Poll::Pending` means that this stream's next value is not ready
|
||||
/// yet. Implementations will ensure that the current task will be notified
|
||||
/// when the next value may be ready.
|
||||
///
|
||||
/// - `Poll::Ready(Some(val))` means that the stream has successfully
|
||||
/// produced a value, `val`, and may produce further values on subsequent
|
||||
/// `poll_next` calls.
|
||||
///
|
||||
/// - `Poll::Ready(None)` means that the stream has terminated, and
|
||||
/// `poll_next` should not be invoked again.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Once a stream has finished (returned `Ready(None)` from `poll_next`), calling its
|
||||
/// `poll_next` method again may panic, block forever, or cause other kinds of
|
||||
/// problems; the `Stream` trait places no requirements on the effects of
|
||||
/// such a call. However, as the `poll_next` method is not marked `unsafe`,
|
||||
/// Rust's usual rules apply: calls must never cause undefined behavior
|
||||
/// (memory corruption, incorrect use of `unsafe` functions, or the like),
|
||||
/// regardless of the stream's state.
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
|
||||
|
||||
/// Returns the bounds on the remaining length of the stream.
|
||||
///
|
||||
/// Specifically, `size_hint()` returns a tuple where the first element
|
||||
/// is the lower bound, and the second element is the upper bound.
|
||||
///
|
||||
/// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`.
|
||||
/// A [`None`] here means that either there is no known upper bound, or the
|
||||
/// upper bound is larger than [`usize`].
|
||||
///
|
||||
/// # Implementation notes
|
||||
///
|
||||
/// It is not enforced that a stream implementation yields the declared
|
||||
/// number of elements. A buggy stream may yield less than the lower bound
|
||||
/// or more than the upper bound of elements.
|
||||
///
|
||||
/// `size_hint()` is primarily intended to be used for optimizations such as
|
||||
/// reserving space for the elements of the stream, but must not be
|
||||
/// trusted to e.g., omit bounds checks in unsafe code. An incorrect
|
||||
/// implementation of `size_hint()` should not lead to memory safety
|
||||
/// violations.
|
||||
///
|
||||
/// That said, the implementation should provide a correct estimation,
|
||||
/// because otherwise it would be a violation of the trait's protocol.
|
||||
///
|
||||
/// The default implementation returns `(0, `[`None`]`)` which is correct for any
|
||||
/// stream.
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, None)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_stream", issue = "79024")]
|
||||
impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
|
||||
type Item = S::Item;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
S::poll_next(Pin::new(&mut **self), cx)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(**self).size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_stream", issue = "79024")]
|
||||
impl<P> Stream for Pin<P>
|
||||
where
|
||||
P: DerefMut + Unpin,
|
||||
P::Target: Stream,
|
||||
{
|
||||
type Item = <P::Target as Stream>::Item;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.get_mut().as_mut().poll_next(cx)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(**self).size_hint()
|
||||
}
|
||||
}
|
@ -224,6 +224,7 @@
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(allow_internal_unsafe)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(async_stream)]
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(array_error_internals)]
|
||||
#![feature(asm)]
|
||||
@ -298,7 +299,6 @@
|
||||
#![feature(prelude_import)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(raw)]
|
||||
#![feature(raw_ref_macros)]
|
||||
#![feature(ready_macro)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustc_private)]
|
||||
@ -450,6 +450,8 @@ pub use core::ptr;
|
||||
pub use core::raw;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::result;
|
||||
#[unstable(feature = "async_stream", issue = "79024")]
|
||||
pub use core::stream;
|
||||
#[stable(feature = "i128", since = "1.26.0")]
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
pub use core::u128;
|
||||
|
@ -12,6 +12,7 @@ use crate::panicking;
|
||||
use crate::pin::Pin;
|
||||
use crate::ptr::{NonNull, Unique};
|
||||
use crate::rc::Rc;
|
||||
use crate::stream::Stream;
|
||||
use crate::sync::atomic;
|
||||
use crate::sync::{Arc, Mutex, RwLock};
|
||||
use crate::task::{Context, Poll};
|
||||
@ -340,6 +341,19 @@ impl<F: Future> Future for AssertUnwindSafe<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "async_stream", issue = "79024")]
|
||||
impl<S: Stream> Stream for AssertUnwindSafe<S> {
|
||||
type Item = S::Item;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
|
||||
unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
/// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
|
||||
///
|
||||
/// This function will return `Ok` with the closure's result if the closure
|
||||
|
@ -194,7 +194,8 @@ def default_build_triple(verbose):
|
||||
# being detected as GNU instead of MSVC.
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
try:
|
||||
version = subprocess.check_output(["rustc", "--version", "--verbose"])
|
||||
version = subprocess.check_output(["rustc", "--version", "--verbose"],
|
||||
stderr=subprocess.DEVNULL)
|
||||
version = version.decode(default_encoding)
|
||||
host = next(x for x in version.split('\n') if x.startswith("host: "))
|
||||
triple = host.split("host: ")[1]
|
||||
@ -1085,10 +1086,10 @@ def bootstrap(help_triggered):
|
||||
else:
|
||||
build.set_normal_environment()
|
||||
|
||||
build.build = args.build or build.build_triple()
|
||||
build.update_submodules()
|
||||
|
||||
# Fetch/build the bootstrap
|
||||
build.build = args.build or build.build_triple()
|
||||
build.download_stage0()
|
||||
sys.stdout.flush()
|
||||
build.ensure_vendored()
|
||||
|
@ -1436,8 +1436,7 @@ impl Type {
|
||||
Array(..) => PrimitiveType::Array,
|
||||
RawPointer(..) => PrimitiveType::RawPointer,
|
||||
QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
|
||||
// FIXME: remove this wildcard
|
||||
_ => return None,
|
||||
Generic(_) | Infer | ImplTrait(_) => return None,
|
||||
};
|
||||
cache.and_then(|c| Primitive(t).def_id_full(c))
|
||||
}
|
||||
|
@ -35,6 +35,12 @@ crate enum OutputFormat {
|
||||
Html,
|
||||
}
|
||||
|
||||
impl Default for OutputFormat {
|
||||
fn default() -> OutputFormat {
|
||||
OutputFormat::Html
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputFormat {
|
||||
crate fn is_json(&self) -> bool {
|
||||
matches!(self, OutputFormat::Json)
|
||||
@ -118,7 +124,7 @@ crate struct Options {
|
||||
crate enable_per_target_ignores: bool,
|
||||
|
||||
/// The path to a rustc-like binary to build tests with. If not set, we
|
||||
/// default to loading from $sysroot/bin/rustc.
|
||||
/// default to loading from `$sysroot/bin/rustc`.
|
||||
crate test_builder: Option<PathBuf>,
|
||||
|
||||
// Options that affect the documentation process
|
||||
@ -142,8 +148,10 @@ crate struct Options {
|
||||
crate crate_version: Option<String>,
|
||||
/// Collected options specific to outputting final pages.
|
||||
crate render_options: RenderOptions,
|
||||
/// Output format rendering (used only for "show-coverage" option for the moment)
|
||||
crate output_format: Option<OutputFormat>,
|
||||
/// The format that we output when rendering.
|
||||
///
|
||||
/// Currently used only for the `--show-coverage` option.
|
||||
crate output_format: OutputFormat,
|
||||
/// If this option is set to `true`, rustdoc will only run checks and not generate
|
||||
/// documentation.
|
||||
crate run_check: bool,
|
||||
@ -271,7 +279,7 @@ crate struct RenderInfo {
|
||||
crate deref_trait_did: Option<DefId>,
|
||||
crate deref_mut_trait_did: Option<DefId>,
|
||||
crate owned_box_did: Option<DefId>,
|
||||
crate output_format: Option<OutputFormat>,
|
||||
crate output_format: OutputFormat,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
@ -537,28 +545,28 @@ impl Options {
|
||||
|
||||
let output_format = match matches.opt_str("output-format") {
|
||||
Some(s) => match OutputFormat::try_from(s.as_str()) {
|
||||
Ok(o) => {
|
||||
if o.is_json()
|
||||
Ok(out_fmt) => {
|
||||
if out_fmt.is_json()
|
||||
&& !(show_coverage || nightly_options::match_is_nightly_build(matches))
|
||||
{
|
||||
diag.struct_err("json output format isn't supported for doc generation")
|
||||
.emit();
|
||||
return Err(1);
|
||||
} else if !o.is_json() && show_coverage {
|
||||
} else if !out_fmt.is_json() && show_coverage {
|
||||
diag.struct_err(
|
||||
"html output format isn't supported for the --show-coverage option",
|
||||
)
|
||||
.emit();
|
||||
return Err(1);
|
||||
}
|
||||
Some(o)
|
||||
out_fmt
|
||||
}
|
||||
Err(e) => {
|
||||
diag.struct_err(&e).emit();
|
||||
return Err(1);
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
None => OutputFormat::default(),
|
||||
};
|
||||
let crate_name = matches.opt_str("crate-name");
|
||||
let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
|
||||
|
@ -463,7 +463,7 @@ crate fn run_global_ctxt(
|
||||
mut default_passes: passes::DefaultPassOption,
|
||||
mut manual_passes: Vec<String>,
|
||||
render_options: RenderOptions,
|
||||
output_format: Option<OutputFormat>,
|
||||
output_format: OutputFormat,
|
||||
) -> (clean::Crate, RenderInfo, RenderOptions) {
|
||||
// Certain queries assume that some checks were run elsewhere
|
||||
// (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
|
||||
|
@ -578,7 +578,7 @@ fn main_options(options: config::Options) -> MainResult {
|
||||
let (error_format, edition, debugging_options) = diag_opts;
|
||||
let diag = core::new_handler(error_format, None, &debugging_options);
|
||||
match output_format {
|
||||
None | Some(config::OutputFormat::Html) => sess.time("render_html", || {
|
||||
config::OutputFormat::Html => sess.time("render_html", || {
|
||||
run_renderer::<html::render::Context<'_>>(
|
||||
krate,
|
||||
render_opts,
|
||||
@ -588,7 +588,7 @@ fn main_options(options: config::Options) -> MainResult {
|
||||
tcx,
|
||||
)
|
||||
}),
|
||||
Some(config::OutputFormat::Json) => sess.time("render_json", || {
|
||||
config::OutputFormat::Json => sess.time("render_json", || {
|
||||
run_renderer::<json::JsonRenderer<'_>>(
|
||||
krate,
|
||||
render_opts,
|
||||
|
@ -132,7 +132,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> {
|
||||
|
||||
fn print_results(&self) {
|
||||
let output_format = self.ctx.renderinfo.borrow().output_format;
|
||||
if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) {
|
||||
if output_format.is_json() {
|
||||
println!("{}", self.to_json());
|
||||
return;
|
||||
}
|
||||
|
13
src/test/codegen/abi-repr-ext.rs
Normal file
13
src/test/codegen/abi-repr-ext.rs
Normal file
@ -0,0 +1,13 @@
|
||||
#![crate_type="lib"]
|
||||
|
||||
#[repr(i8)]
|
||||
pub enum Type {
|
||||
Type1 = 0,
|
||||
Type2 = 1
|
||||
}
|
||||
|
||||
// CHECK: define signext i8 @test()
|
||||
#[no_mangle]
|
||||
pub extern "C" fn test() -> Type {
|
||||
Type::Type1
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
// run-pass
|
||||
// pretty-expanded FIXME #23616
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub fn main() {
|
||||
struct A {
|
||||
|
@ -0,0 +1,38 @@
|
||||
// run-pass
|
||||
// aux-build:ver-cfg-rel.rs
|
||||
// revisions: assume no_assume
|
||||
// [assume]compile-flags: -Z assume-incomplete-release
|
||||
|
||||
#![feature(cfg_version)]
|
||||
|
||||
extern crate ver_cfg_rel;
|
||||
|
||||
use ver_cfg_rel::ver_cfg_rel;
|
||||
|
||||
#[ver_cfg_rel("-2")]
|
||||
fn foo_2() { }
|
||||
|
||||
#[ver_cfg_rel("-1")]
|
||||
fn foo_1() { }
|
||||
|
||||
#[cfg(assume)]
|
||||
#[ver_cfg_rel("0")]
|
||||
fn foo() { compile_error!("wrong+0") }
|
||||
|
||||
#[cfg(no_assume)]
|
||||
#[ver_cfg_rel("0")]
|
||||
fn foo() { }
|
||||
|
||||
#[ver_cfg_rel("1")]
|
||||
fn bar() { compile_error!("wrong+1") }
|
||||
|
||||
#[ver_cfg_rel("2")]
|
||||
fn bar() { compile_error!("wrong+2") }
|
||||
|
||||
fn main() {
|
||||
foo_2();
|
||||
foo_1();
|
||||
|
||||
#[cfg(no_assume)]
|
||||
foo();
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::{TokenStream, TokenTree as Tt};
|
||||
use std::str::FromStr;
|
||||
|
||||
// String containing the current version number of the tip, i.e. "1.41.2"
|
||||
static VERSION_NUMBER: &str = include_str!("../../../../../version");
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Version {
|
||||
major: i16,
|
||||
minor: i16,
|
||||
patch: i16,
|
||||
}
|
||||
|
||||
fn parse_version(s: &str) -> Option<Version> {
|
||||
let mut digits = s.splitn(3, '.');
|
||||
let major = digits.next()?.parse().ok()?;
|
||||
let minor = digits.next()?.parse().ok()?;
|
||||
let patch = digits.next().unwrap_or("0").trim().parse().ok()?;
|
||||
Some(Version { major, minor, patch })
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
/// Emits a #[cfg(version)] relative to the current one, so passing
|
||||
/// -1 as argument on compiler 1.50 will emit #[cfg(version("1.49.0"))],
|
||||
/// while 1 will emit #[cfg(version("1.51.0"))]
|
||||
pub fn ver_cfg_rel(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut v_rel = None;
|
||||
for a in attr.into_iter() {
|
||||
match a {
|
||||
Tt::Literal(l) => {
|
||||
let mut s = l.to_string();
|
||||
let s = s.trim_matches('"');
|
||||
let v: i16 = s.parse().unwrap();
|
||||
v_rel = Some(v);
|
||||
break;
|
||||
},
|
||||
_ => panic!("{:?}", a),
|
||||
}
|
||||
}
|
||||
let v_rel = v_rel.unwrap();
|
||||
|
||||
let mut v = parse_version(VERSION_NUMBER).unwrap();
|
||||
v.minor += v_rel;
|
||||
|
||||
let attr_str = format!("#[cfg(version(\"{}.{}.{}\"))]", v.major, v.minor, v.patch);
|
||||
let mut res = Vec::<Tt>::new();
|
||||
res.extend(TokenStream::from_str(&attr_str).unwrap().into_iter());
|
||||
res.extend(input.into_iter());
|
||||
res.into_iter().collect()
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
// run-pass
|
||||
|
||||
// Test that functional record update/struct update syntax works inside
|
||||
// a closure when the feature `capture_disjoint_fields` is enabled.
|
||||
|
||||
#![feature(capture_disjoint_fields)]
|
||||
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
|
||||
//~| NOTE: `#[warn(incomplete_features)]` on by default
|
||||
//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S {
|
||||
a: String,
|
||||
b: String,
|
||||
}
|
||||
|
||||
struct T {
|
||||
a: String,
|
||||
s: S,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = String::new();
|
||||
let b = String::new();
|
||||
let c = String::new();
|
||||
let s = S {a, b};
|
||||
let t = T {
|
||||
a: c,
|
||||
s: s.clone()
|
||||
};
|
||||
|
||||
let c = || {
|
||||
let s2 = S {
|
||||
a: format!("New s2"),
|
||||
..s
|
||||
};
|
||||
let s3 = S {
|
||||
a: format!("New s3"),
|
||||
..t.s
|
||||
};
|
||||
println!("{} {}", s2.a, s2.b);
|
||||
println!("{} {} {}", s3.a, s3.b, t.a);
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/fru_syntax.rs:6:12
|
||||
|
|
||||
LL | #![feature(capture_disjoint_fields)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
@ -1,11 +1,10 @@
|
||||
// check-pass
|
||||
#![feature(const_raw_ptr_deref)]
|
||||
#![feature(raw_ref_macros)]
|
||||
|
||||
use std::ptr;
|
||||
|
||||
const fn test_fn(x: *const i32) {
|
||||
let x2 = unsafe { ptr::raw_const!(*x) };
|
||||
let x2 = unsafe { ptr::addr_of!(*x) };
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -9,8 +9,7 @@
|
||||
core_intrinsics,
|
||||
const_raw_ptr_comparison,
|
||||
const_ptr_offset,
|
||||
const_raw_ptr_deref,
|
||||
raw_ref_macros
|
||||
const_raw_ptr_deref
|
||||
)]
|
||||
|
||||
const FOO: &usize = &42;
|
||||
@ -64,7 +63,7 @@ const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
|
||||
|
||||
const _: *const u8 =
|
||||
//~^ NOTE
|
||||
unsafe { std::ptr::raw_const!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
|
||||
unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
|
||||
//~^ ERROR any use of this value will cause an error
|
||||
//~| NOTE
|
||||
|
||||
|
@ -6,9 +6,9 @@ LL | unsafe { intrinsics::offset(self, count) }
|
||||
| |
|
||||
| inbounds test failed: pointer must be in-bounds at offset $TWO_WORDS, but is outside bounds of alloc2 which has size $WORD
|
||||
| inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||
| inside `_` at $DIR/ptr_comparisons.rs:62:34
|
||||
| inside `_` at $DIR/ptr_comparisons.rs:61:34
|
||||
|
|
||||
::: $DIR/ptr_comparisons.rs:62:1
|
||||
::: $DIR/ptr_comparisons.rs:61:1
|
||||
|
|
||||
LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
|
||||
| -------------------------------------------------------------------
|
||||
@ -16,17 +16,17 @@ LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/ptr_comparisons.rs:67:35
|
||||
--> $DIR/ptr_comparisons.rs:66:33
|
||||
|
|
||||
LL | / const _: *const u8 =
|
||||
LL | |
|
||||
LL | | unsafe { std::ptr::raw_const!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
|
||||
| |___________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^___-
|
||||
| |
|
||||
| memory access failed: pointer must be in-bounds at offset 1000, but is outside bounds of alloc2 which has size $WORD
|
||||
LL | | unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
|
||||
| |_________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^___-
|
||||
| |
|
||||
| memory access failed: pointer must be in-bounds at offset 1000, but is outside bounds of alloc2 which has size $WORD
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/ptr_comparisons.rs:71:27
|
||||
--> $DIR/ptr_comparisons.rs:70:27
|
||||
|
|
||||
LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
|
||||
| --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
|
||||
@ -34,7 +34,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
|
||||
| "pointer-to-integer cast" needs an rfc before being allowed inside constants
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/ptr_comparisons.rs:76:27
|
||||
--> $DIR/ptr_comparisons.rs:75:27
|
||||
|
|
||||
LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
|
||||
| --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
|
||||
|
20
src/test/ui/lint/dead-code/write-only-field.rs
Normal file
20
src/test/ui/lint/dead-code/write-only-field.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![deny(dead_code)]
|
||||
|
||||
struct S {
|
||||
f: i32, //~ ERROR: field is never read
|
||||
sub: Sub, //~ ERROR: field is never read
|
||||
}
|
||||
|
||||
struct Sub {
|
||||
f: i32, //~ ERROR: field is never read
|
||||
}
|
||||
|
||||
fn field_write(s: &mut S) {
|
||||
s.f = 1;
|
||||
s.sub.f = 2;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut s = S { f: 0, sub: Sub { f: 0 } };
|
||||
field_write(&mut s);
|
||||
}
|
26
src/test/ui/lint/dead-code/write-only-field.stderr
Normal file
26
src/test/ui/lint/dead-code/write-only-field.stderr
Normal file
@ -0,0 +1,26 @@
|
||||
error: field is never read: `f`
|
||||
--> $DIR/write-only-field.rs:4:5
|
||||
|
|
||||
LL | f: i32,
|
||||
| ^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/write-only-field.rs:1:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: field is never read: `sub`
|
||||
--> $DIR/write-only-field.rs:5:5
|
||||
|
|
||||
LL | sub: Sub,
|
||||
| ^^^^^^^^
|
||||
|
||||
error: field is never read: `f`
|
||||
--> $DIR/write-only-field.rs:9:5
|
||||
|
|
||||
LL | f: i32,
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 216a64300563351cad20bb3847110c14561687e0
|
||||
Subproject commit ea268b9f559fbafcfc24f4982173b01dfad9e443
|
Loading…
x
Reference in New Issue
Block a user