Auto merge of #77004 - RalfJung:rollup-usac4nv, r=RalfJung
Rollup of 13 pull requests Successful merges: - #76135 (Stabilize some Option methods as const) - #76628 (Add sample defaults for config.toml ) - #76846 (Avoiding unnecesary allocations at rustc_errors) - #76867 (Use intra-doc links in core/src/iter when possible) - #76868 (Finish moving to intra doc links for std::sync) - #76872 (Remove DeclareMethods) - #76936 (Add non-`unsafe` `.get_mut()` for `Unsafecell`) - #76958 (Replace manual as_nanos and as_secs_f64 reimplementations) - #76959 (Replace write_fmt with write!) - #76961 (Add test for issue #34634) - #76962 (Use const_cstr macro in consts.rs) - #76963 (Remove unused static_assert macro) - #77000 (update Miri) Failed merges: r? `@ghost`
This commit is contained in:
commit
956e06c6c8
23
Cargo.lock
23
Cargo.lock
@ -207,6 +207,7 @@ dependencies = [
|
||||
"ignore",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"merge",
|
||||
"num_cpus",
|
||||
"opener",
|
||||
"pretty_assertions",
|
||||
@ -1909,6 +1910,28 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "merge"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"
|
||||
dependencies = [
|
||||
"merge_derive",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "merge_derive"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minifier"
|
||||
version = "0.0.33"
|
||||
|
@ -108,7 +108,7 @@ pub fn compile_codegen_unit(
|
||||
|
||||
// We assume that the cost to run LLVM on a CGU is proportional to
|
||||
// the time we needed for codegenning it.
|
||||
let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
|
||||
let cost = time_to_codegen.as_nanos() as u64;
|
||||
|
||||
fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
|
@ -7,6 +7,7 @@ use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
use libc::c_uint;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::const_cstr;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::Node;
|
||||
@ -22,8 +23,6 @@ use rustc_span::Span;
|
||||
use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
|
||||
use tracing::debug;
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
|
||||
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
|
||||
let dl = cx.data_layout();
|
||||
@ -454,9 +453,9 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
|
||||
.all(|&byte| byte == 0);
|
||||
|
||||
let sect_name = if all_bytes_are_zero {
|
||||
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0")
|
||||
const_cstr!("__DATA,__thread_bss")
|
||||
} else {
|
||||
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0")
|
||||
const_cstr!("__DATA,__thread_data")
|
||||
};
|
||||
llvm::LLVMSetSection(g, sect_name.as_ptr());
|
||||
}
|
||||
|
@ -433,6 +433,17 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
llvm::LLVMSetSection(g, section.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
||||
if self.get_declared_value("main").is_none() {
|
||||
Some(self.declare_cfn("main", fn_type))
|
||||
} else {
|
||||
// If the symbol already exists, it is an error: for example, the user wrote
|
||||
// #[no_mangle] extern "C" fn main(..) {..}
|
||||
// instead of #[start]
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CodegenCx<'b, 'tcx> {
|
||||
|
@ -51,17 +51,32 @@ fn declare_raw_fn(
|
||||
llfn
|
||||
}
|
||||
|
||||
impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
|
||||
impl CodegenCx<'ll, 'tcx> {
|
||||
/// Declare a global value.
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// return its Value instead.
|
||||
pub fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
|
||||
debug!("declare_global(name={:?})", name);
|
||||
unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) }
|
||||
}
|
||||
|
||||
fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value {
|
||||
/// Declare a C ABI function.
|
||||
///
|
||||
/// Only use this for foreign function ABIs and glue. For Rust functions use
|
||||
/// `declare_fn` instead.
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
pub fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value {
|
||||
declare_raw_fn(self, name, llvm::CCallConv, fn_type)
|
||||
}
|
||||
|
||||
fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value {
|
||||
/// Declare a Rust function.
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value {
|
||||
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
|
||||
|
||||
let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self));
|
||||
@ -69,7 +84,13 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
llfn
|
||||
}
|
||||
|
||||
fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> {
|
||||
/// Declare a global with an intention to define it.
|
||||
///
|
||||
/// Use this function when you intend to define a global. This function will
|
||||
/// return `None` if the name already has a definition associated with it. In that
|
||||
/// case an error should be reported to the user, because it usually happens due
|
||||
/// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes).
|
||||
pub fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> {
|
||||
if self.get_defined_value(name).is_some() {
|
||||
None
|
||||
} else {
|
||||
@ -77,16 +98,22 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn define_private_global(&self, ty: &'ll Type) -> &'ll Value {
|
||||
/// Declare a private global
|
||||
///
|
||||
/// Use this function when you intend to define a global without a name.
|
||||
pub fn define_private_global(&self, ty: &'ll Type) -> &'ll Value {
|
||||
unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) }
|
||||
}
|
||||
|
||||
fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
|
||||
/// Gets declared value by name.
|
||||
pub fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
|
||||
debug!("get_declared_value(name={:?})", name);
|
||||
unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) }
|
||||
}
|
||||
|
||||
fn get_defined_value(&self, name: &str) -> Option<&'ll Value> {
|
||||
/// Gets defined or externally defined (AvailableExternally linkage) value by
|
||||
/// name.
|
||||
pub fn get_defined_value(&self, name: &str) -> Option<&'ll Value> {
|
||||
self.get_declared_value(name).and_then(|val| {
|
||||
let declaration = unsafe { llvm::LLVMIsDeclaration(val) != 0 };
|
||||
if !declaration { Some(val) } else { None }
|
||||
|
@ -407,16 +407,18 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
// listing.
|
||||
let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap());
|
||||
|
||||
if cx.get_declared_value("main").is_some() {
|
||||
// FIXME: We should be smart and show a better diagnostic here.
|
||||
cx.sess()
|
||||
.struct_span_err(sp, "entry symbol `main` declared multiple times")
|
||||
.help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
|
||||
.emit();
|
||||
cx.sess().abort_if_errors();
|
||||
bug!();
|
||||
}
|
||||
let llfn = cx.declare_cfn("main", llfty);
|
||||
let llfn = match cx.declare_c_main(llfty) {
|
||||
Some(llfn) => llfn,
|
||||
None => {
|
||||
// FIXME: We should be smart and show a better diagnostic here.
|
||||
cx.sess()
|
||||
.struct_span_err(sp, "entry symbol `main` declared multiple times")
|
||||
.help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
|
||||
.emit();
|
||||
cx.sess().abort_if_errors();
|
||||
bug!();
|
||||
}
|
||||
};
|
||||
|
||||
// `main` should respect same config for frame pointer elimination as rest of code
|
||||
cx.set_frame_pointer_elimination(llfn);
|
||||
|
@ -1,51 +1,7 @@
|
||||
use super::BackendTypes;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::mono::{Linkage, Visibility};
|
||||
use rustc_middle::ty::{Instance, Ty};
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
|
||||
pub trait DeclareMethods<'tcx>: BackendTypes {
|
||||
/// Declare a global value.
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// return its Value instead.
|
||||
fn declare_global(&self, name: &str, ty: Self::Type) -> Self::Value;
|
||||
|
||||
/// Declare a C ABI function.
|
||||
///
|
||||
/// Only use this for foreign function ABIs and glue. For Rust functions use
|
||||
/// `declare_fn` instead.
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Function;
|
||||
|
||||
/// Declare a Rust function.
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Function;
|
||||
|
||||
/// Declare a global with an intention to define it.
|
||||
///
|
||||
/// Use this function when you intend to define a global. This function will
|
||||
/// return `None` if the name already has a definition associated with it. In that
|
||||
/// case an error should be reported to the user, because it usually happens due
|
||||
/// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes).
|
||||
fn define_global(&self, name: &str, ty: Self::Type) -> Option<Self::Value>;
|
||||
|
||||
/// Declare a private global
|
||||
///
|
||||
/// Use this function when you intend to define a global without a name.
|
||||
fn define_private_global(&self, ty: Self::Type) -> Self::Value;
|
||||
|
||||
/// Gets declared value by name.
|
||||
fn get_declared_value(&self, name: &str) -> Option<Self::Value>;
|
||||
|
||||
/// Gets defined or externally defined (AvailableExternally linkage) value by
|
||||
/// name.
|
||||
fn get_defined_value(&self, name: &str) -> Option<Self::Value>;
|
||||
}
|
||||
use rustc_middle::ty::Instance;
|
||||
|
||||
pub trait PreDefineMethods<'tcx>: BackendTypes {
|
||||
fn predefine_static(
|
||||
|
@ -19,4 +19,6 @@ pub trait MiscMethods<'tcx>: BackendTypes {
|
||||
fn set_frame_pointer_elimination(&self, llfn: Self::Function);
|
||||
fn apply_target_cpu_attr(&self, llfn: Self::Function);
|
||||
fn create_used_variable(&self);
|
||||
/// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists.
|
||||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function>;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ pub use self::builder::{BuilderMethods, OverflowOp};
|
||||
pub use self::consts::ConstMethods;
|
||||
pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods};
|
||||
pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods};
|
||||
pub use self::declare::{DeclareMethods, PreDefineMethods};
|
||||
pub use self::declare::PreDefineMethods;
|
||||
pub use self::intrinsic::IntrinsicCallMethods;
|
||||
pub use self::misc::MiscMethods;
|
||||
pub use self::statics::{StaticBuilderMethods, StaticMethods};
|
||||
@ -60,7 +60,6 @@ pub trait CodegenMethods<'tcx>:
|
||||
+ StaticMethods
|
||||
+ CoverageInfoMethods
|
||||
+ DebugInfoMethods<'tcx>
|
||||
+ DeclareMethods<'tcx>
|
||||
+ AsmMethods
|
||||
+ PreDefineMethods<'tcx>
|
||||
+ HasParamEnv<'tcx>
|
||||
@ -77,7 +76,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
|
||||
+ StaticMethods
|
||||
+ CoverageInfoMethods
|
||||
+ DebugInfoMethods<'tcx>
|
||||
+ DeclareMethods<'tcx>
|
||||
+ AsmMethods
|
||||
+ PreDefineMethods<'tcx>
|
||||
+ HasParamEnv<'tcx>
|
||||
|
@ -1,15 +1,3 @@
|
||||
/// A simple static assertion macro.
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(type_ascription)]
|
||||
macro_rules! static_assert {
|
||||
($test:expr) => {
|
||||
// Use the bool to access an array such that if the bool is false, the access
|
||||
// is out-of-bounds.
|
||||
#[allow(dead_code)]
|
||||
const _: () = [()][!($test: bool) as usize];
|
||||
};
|
||||
}
|
||||
|
||||
/// Type size assertion. The first argument is a type and the second argument is its expected size.
|
||||
#[macro_export]
|
||||
macro_rules! static_assert_size {
|
||||
|
@ -600,10 +600,7 @@ pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) {
|
||||
// Hack up our own formatting for the duration to make it easier for scripts
|
||||
// to parse (always use the same number of decimal places and the same unit).
|
||||
pub fn duration_to_secs_str(dur: std::time::Duration) -> String {
|
||||
const NANOS_PER_SEC: f64 = 1_000_000_000.0;
|
||||
let secs = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / NANOS_PER_SEC;
|
||||
|
||||
format!("{:.3}", secs)
|
||||
format!("{:.3}", dur.as_secs_f64())
|
||||
}
|
||||
|
||||
// Memory reporting
|
||||
|
@ -1227,18 +1227,14 @@ impl EmitterWriter {
|
||||
}
|
||||
draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
|
||||
if *level != Level::FailureNote {
|
||||
let level_str = level.to_string();
|
||||
if !level_str.is_empty() {
|
||||
buffer.append(0, &level_str, Style::MainHeaderMsg);
|
||||
buffer.append(0, ": ", Style::NoStyle);
|
||||
}
|
||||
buffer.append(0, level.to_str(), Style::MainHeaderMsg);
|
||||
buffer.append(0, ": ", Style::NoStyle);
|
||||
}
|
||||
self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
|
||||
} else {
|
||||
let level_str = level.to_string();
|
||||
// The failure note level itself does not provide any useful diagnostic information
|
||||
if *level != Level::FailureNote && !level_str.is_empty() {
|
||||
buffer.append(0, &level_str, Style::Level(*level));
|
||||
if *level != Level::FailureNote {
|
||||
buffer.append(0, level.to_str(), Style::Level(*level));
|
||||
}
|
||||
// only render error codes, not lint codes
|
||||
if let Some(DiagnosticId::Error(ref code)) = *code {
|
||||
@ -1246,7 +1242,7 @@ impl EmitterWriter {
|
||||
buffer.append(0, &code, Style::Level(*level));
|
||||
buffer.append(0, "]", Style::Level(*level));
|
||||
}
|
||||
if *level != Level::FailureNote && !level_str.is_empty() {
|
||||
if *level != Level::FailureNote {
|
||||
buffer.append(0, ": ", header_style);
|
||||
}
|
||||
for &(ref text, _) in msg.iter() {
|
||||
@ -1548,11 +1544,9 @@ impl EmitterWriter {
|
||||
let mut buffer = StyledBuffer::new();
|
||||
|
||||
// Render the suggestion message
|
||||
let level_str = level.to_string();
|
||||
if !level_str.is_empty() {
|
||||
buffer.append(0, &level_str, Style::Level(*level));
|
||||
buffer.append(0, ": ", Style::HeaderMsg);
|
||||
}
|
||||
buffer.append(0, level.to_str(), Style::Level(*level));
|
||||
buffer.append(0, ": ", Style::HeaderMsg);
|
||||
|
||||
self.msg_to_buffer(
|
||||
&mut buffer,
|
||||
&[(suggestion.msg.to_owned(), Style::NoStyle)],
|
||||
|
@ -973,16 +973,14 @@ impl HandlerInner {
|
||||
|
||||
fn panic_if_treat_err_as_bug(&self) {
|
||||
if self.treat_err_as_bug() {
|
||||
let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
|
||||
(0, _) => return,
|
||||
(1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(),
|
||||
(1, _) => return,
|
||||
(count, as_bug) => format!(
|
||||
match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
|
||||
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
|
||||
(0, _) | (1, _) => {}
|
||||
(count, as_bug) => panic!(
|
||||
"aborting after {} errors due to `-Z treat-err-as-bug={}`",
|
||||
count, as_bug,
|
||||
),
|
||||
};
|
||||
panic!(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,16 @@
|
||||
# a custom configuration file can also be specified with `--config` to the build
|
||||
# system.
|
||||
|
||||
# =============================================================================
|
||||
# Global Settings
|
||||
# =============================================================================
|
||||
|
||||
# Use different pre-set defaults than the global defaults.
|
||||
#
|
||||
# See `src/bootstrap/defaults` for more information.
|
||||
# Note that this has no default value (x.py uses the defaults in `config.toml.example`).
|
||||
#profile = <none>
|
||||
|
||||
# =============================================================================
|
||||
# Tweaking how LLVM is compiled
|
||||
# =============================================================================
|
||||
|
@ -496,10 +496,7 @@ impl<T: ?Sized> Cell<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "cell_get_mut", since = "1.11.0")]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
// SAFETY: This can cause data races if called from a separate thread,
|
||||
// but `Cell` is `!Sync` so this won't happen, and `&mut` guarantees
|
||||
// unique access.
|
||||
unsafe { &mut *self.value.get() }
|
||||
self.value.get_mut()
|
||||
}
|
||||
|
||||
/// Returns a `&Cell<T>` from a `&mut T`
|
||||
@ -945,8 +942,7 @@ impl<T: ?Sized> RefCell<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "cell_get_mut", since = "1.11.0")]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
// SAFETY: `&mut` guarantees unique access.
|
||||
unsafe { &mut *self.value.get() }
|
||||
self.value.get_mut()
|
||||
}
|
||||
|
||||
/// Undo the effect of leaked guards on the borrow state of the `RefCell`.
|
||||
@ -1543,8 +1539,11 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
|
||||
/// allow internal mutability, such as `Cell<T>` and `RefCell<T>`, use `UnsafeCell` to wrap their
|
||||
/// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell<T>`.
|
||||
///
|
||||
/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to
|
||||
/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly.
|
||||
/// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer
|
||||
/// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer
|
||||
/// correctly.
|
||||
///
|
||||
/// [`.get()`]: `UnsafeCell::get`
|
||||
///
|
||||
/// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious:
|
||||
///
|
||||
@ -1571,21 +1570,70 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
|
||||
/// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T`
|
||||
/// co-exist with it. A `&mut T` must always be unique.
|
||||
///
|
||||
/// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell<T>` is
|
||||
/// ok (provided you enforce the invariants some other way), it is still undefined behavior
|
||||
/// to have multiple `&mut UnsafeCell<T>` aliases.
|
||||
/// Note that whilst mutating the contents of an `&UnsafeCell<T>` (even while other
|
||||
/// `&UnsafeCell<T>` references alias the cell) is
|
||||
/// ok (provided you enforce the above invariants some other way), it is still undefined behavior
|
||||
/// to have multiple `&mut UnsafeCell<T>` aliases. That is, `UnsafeCell` is a wrapper
|
||||
/// designed to have a special interaction with _shared_ accesses (_i.e._, through an
|
||||
/// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_
|
||||
/// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value
|
||||
/// may be aliased for the duration of that `&mut` borrow.
|
||||
/// This is showcased by the [`.get_mut()`] accessor, which is a non-`unsafe` getter that yields
|
||||
/// a `&mut T`.
|
||||
///
|
||||
/// [`.get_mut()`]: `UnsafeCell::get_mut`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Here is an example showcasing how to soundly mutate the contents of an `UnsafeCell<_>` despite
|
||||
/// there being multiple references aliasing the cell:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cell::UnsafeCell;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// struct NotThreadSafe<T> {
|
||||
/// value: UnsafeCell<T>,
|
||||
/// }
|
||||
/// let x: UnsafeCell<i32> = 42.into();
|
||||
/// // Get multiple / concurrent / shared references to the same `x`.
|
||||
/// let (p1, p2): (&UnsafeCell<i32>, &UnsafeCell<i32>) = (&x, &x);
|
||||
///
|
||||
/// unsafe impl<T> Sync for NotThreadSafe<T> {}
|
||||
/// unsafe {
|
||||
/// // SAFETY: within this scope there are no other references to `x`'s contents,
|
||||
/// // so ours is effectively unique.
|
||||
/// let p1_exclusive: &mut i32 = &mut *p1.get(); // -- borrow --+
|
||||
/// *p1_exclusive += 27; // |
|
||||
/// } // <---------- cannot go beyond this point -------------------+
|
||||
///
|
||||
/// unsafe {
|
||||
/// // SAFETY: within this scope nobody expects to have exclusive access to `x`'s contents,
|
||||
/// // so we can have multiple shared accesses concurrently.
|
||||
/// let p2_shared: &i32 = &*p2.get();
|
||||
/// assert_eq!(*p2_shared, 42 + 27);
|
||||
/// let p1_shared: &i32 = &*p1.get();
|
||||
/// assert_eq!(*p1_shared, *p2_shared);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The following example showcases the fact that exclusive access to an `UnsafeCell<T>`
|
||||
/// implies exclusive access to its `T`:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(unsafe_cell_get_mut)]
|
||||
/// #![forbid(unsafe_code)] // with exclusive accesses,
|
||||
/// // `UnsafeCell` is a transparent no-op wrapper,
|
||||
/// // so no need for `unsafe` here.
|
||||
/// use std::cell::UnsafeCell;
|
||||
///
|
||||
/// let mut x: UnsafeCell<i32> = 42.into();
|
||||
///
|
||||
/// // Get a compile-time-checked unique reference to `x`.
|
||||
/// let p_unique: &mut UnsafeCell<i32> = &mut x;
|
||||
/// // With an exclusive reference, we can mutate the contents for free.
|
||||
/// *p_unique.get_mut() = 0;
|
||||
/// // Or, equivalently:
|
||||
/// x = UnsafeCell::new(0);
|
||||
///
|
||||
/// // When we own the value, we can extract the contents for free.
|
||||
/// let contents: i32 = x.into_inner();
|
||||
/// assert_eq!(contents, 0);
|
||||
/// ```
|
||||
#[lang = "unsafe_cell"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1663,6 +1711,29 @@ impl<T: ?Sized> UnsafeCell<T> {
|
||||
self as *const UnsafeCell<T> as *const T as *mut T
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying data.
|
||||
///
|
||||
/// This call borrows the `UnsafeCell` mutably (at compile-time) which
|
||||
/// guarantees that we possess the only reference.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(unsafe_cell_get_mut)]
|
||||
/// use std::cell::UnsafeCell;
|
||||
///
|
||||
/// let mut c = UnsafeCell::new(5);
|
||||
/// *c.get_mut() += 1;
|
||||
///
|
||||
/// assert_eq!(*c.get_mut(), 6);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "unsafe_cell_get_mut", issue = "76943")]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
// SAFETY: (outer) `&mut` guarantees unique access.
|
||||
unsafe { &mut *self.get() }
|
||||
}
|
||||
|
||||
/// Gets a mutable pointer to the wrapped value.
|
||||
/// The difference to [`get`] is that this function accepts a raw pointer,
|
||||
/// which is useful to avoid the creation of temporary references.
|
||||
|
@ -5,9 +5,7 @@ use super::{FusedIterator, TrustedLen};
|
||||
|
||||
/// An iterator that repeats an element endlessly.
|
||||
///
|
||||
/// This `struct` is created by the [`repeat`] function. See its documentation for more.
|
||||
///
|
||||
/// [`repeat`]: fn.repeat.html
|
||||
/// This `struct` is created by the [`repeat()`] function. See its documentation for more.
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Repeat<A> {
|
||||
@ -47,15 +45,11 @@ unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
|
||||
/// The `repeat()` function repeats a single value over and over again.
|
||||
///
|
||||
/// Infinite iterators like `repeat()` are often used with adapters like
|
||||
/// [`take`], in order to make them finite.
|
||||
///
|
||||
/// [`take`]: trait.Iterator.html#method.take
|
||||
/// [`Iterator::take()`], in order to make them finite.
|
||||
///
|
||||
/// If the element type of the iterator you need does not implement `Clone`,
|
||||
/// or if you do not want to keep the repeated element in memory, you can
|
||||
/// instead use the [`repeat_with`] function.
|
||||
///
|
||||
/// [`repeat_with`]: fn.repeat_with.html
|
||||
/// instead use the [`repeat_with()`] function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -77,7 +71,7 @@ unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
|
||||
/// assert_eq!(Some(4), fours.next());
|
||||
/// ```
|
||||
///
|
||||
/// Going finite with [`take`]:
|
||||
/// Going finite with [`Iterator::take()`]:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter;
|
||||
@ -102,10 +96,8 @@ pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
|
||||
/// An iterator that repeats elements of type `A` endlessly by
|
||||
/// applying the provided closure `F: FnMut() -> A`.
|
||||
///
|
||||
/// This `struct` is created by the [`repeat_with`] function.
|
||||
/// This `struct` is created by the [`repeat_with()`] function.
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`repeat_with`]: fn.repeat_with.html
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
|
||||
pub struct RepeatWith<F> {
|
||||
@ -139,20 +131,18 @@ unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {}
|
||||
/// The `repeat_with()` function calls the repeater over and over again.
|
||||
///
|
||||
/// Infinite iterators like `repeat_with()` are often used with adapters like
|
||||
/// [`take`], in order to make them finite.
|
||||
/// [`Iterator::take()`], in order to make them finite.
|
||||
///
|
||||
/// [`take`]: trait.Iterator.html#method.take
|
||||
///
|
||||
/// If the element type of the iterator you need implements `Clone`, and
|
||||
/// If the element type of the iterator you need implements [`Clone`], and
|
||||
/// it is OK to keep the source element in memory, you should instead use
|
||||
/// the [`repeat`] function.
|
||||
/// the [`repeat()`] function.
|
||||
///
|
||||
/// [`repeat`]: fn.repeat.html
|
||||
///
|
||||
/// An iterator produced by `repeat_with()` is not a `DoubleEndedIterator`.
|
||||
/// If you need `repeat_with()` to return a `DoubleEndedIterator`,
|
||||
/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`].
|
||||
/// If you need `repeat_with()` to return a [`DoubleEndedIterator`],
|
||||
/// please open a GitHub issue explaining your use case.
|
||||
///
|
||||
/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
@ -201,9 +191,7 @@ pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
|
||||
|
||||
/// An iterator that yields nothing.
|
||||
///
|
||||
/// This `struct` is created by the [`empty`] function. See its documentation for more.
|
||||
///
|
||||
/// [`empty`]: fn.empty.html
|
||||
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
pub struct Empty<T>(marker::PhantomData<T>);
|
||||
|
||||
@ -292,9 +280,7 @@ pub const fn empty<T>() -> Empty<T> {
|
||||
|
||||
/// An iterator that yields an element exactly once.
|
||||
///
|
||||
/// This `struct` is created by the [`once`] function. See its documentation for more.
|
||||
///
|
||||
/// [`once`]: fn.once.html
|
||||
/// This `struct` is created by the [`once()`] function. See its documentation for more.
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
pub struct Once<T> {
|
||||
@ -336,12 +322,12 @@ impl<T> FusedIterator for Once<T> {}
|
||||
|
||||
/// Creates an iterator that yields an element exactly once.
|
||||
///
|
||||
/// This is commonly used to adapt a single value into a [`chain`] of other
|
||||
/// This is commonly used to adapt a single value into a [`chain()`] of other
|
||||
/// kinds of iteration. Maybe you have an iterator that covers almost
|
||||
/// everything, but you need an extra special case. Maybe you have a function
|
||||
/// which works on iterators, but you only need to process one value.
|
||||
///
|
||||
/// [`chain`]: trait.Iterator.html#method.chain
|
||||
/// [`chain()`]: Iterator::chain
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -393,10 +379,8 @@ pub fn once<T>(value: T) -> Once<T> {
|
||||
/// An iterator that yields a single element of type `A` by
|
||||
/// applying the provided closure `F: FnOnce() -> A`.
|
||||
///
|
||||
/// This `struct` is created by the [`once_with`] function.
|
||||
/// This `struct` is created by the [`once_with()`] function.
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`once_with`]: fn.once_with.html
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "iter_once_with", since = "1.43.0")]
|
||||
pub struct OnceWith<F> {
|
||||
@ -442,15 +426,14 @@ unsafe impl<A, F: FnOnce() -> A> TrustedLen for OnceWith<F> {}
|
||||
/// Creates an iterator that lazily generates a value exactly once by invoking
|
||||
/// the provided closure.
|
||||
///
|
||||
/// This is commonly used to adapt a single value generator into a [`chain`] of
|
||||
/// This is commonly used to adapt a single value generator into a [`chain()`] of
|
||||
/// other kinds of iteration. Maybe you have an iterator that covers almost
|
||||
/// everything, but you need an extra special case. Maybe you have a function
|
||||
/// which works on iterators, but you only need to process one value.
|
||||
///
|
||||
/// Unlike [`once`], this function will lazily generate the value on request.
|
||||
/// Unlike [`once()`], this function will lazily generate the value on request.
|
||||
///
|
||||
/// [`once`]: fn.once.html
|
||||
/// [`chain`]: trait.Iterator.html#method.chain
|
||||
/// [`chain()`]: Iterator::chain
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -505,17 +488,16 @@ pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
|
||||
///
|
||||
/// This allows creating a custom iterator with any behavior
|
||||
/// without using the more verbose syntax of creating a dedicated type
|
||||
/// and implementing the `Iterator` trait for it.
|
||||
/// and implementing the [`Iterator`] trait for it.
|
||||
///
|
||||
/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure,
|
||||
/// and therefore conservatively does not implement [`FusedIterator`],
|
||||
/// or override [`Iterator::size_hint`] from its default `(0, None)`.
|
||||
///
|
||||
/// [`FusedIterator`]: trait.FusedIterator.html
|
||||
/// [`Iterator::size_hint`]: trait.Iterator.html#method.size_hint
|
||||
/// or override [`Iterator::size_hint()`] from its default `(0, None)`.
|
||||
///
|
||||
/// The closure can use captures and its environment to track state across iterations. Depending on
|
||||
/// how the iterator is used, this may require specifying the `move` keyword on the closure.
|
||||
/// how the iterator is used, this may require specifying the [`move`] keyword on the closure.
|
||||
///
|
||||
/// [`move`]: ../../std/keyword.move.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -549,10 +531,10 @@ where
|
||||
|
||||
/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option<T>`.
|
||||
///
|
||||
/// This `struct` is created by the [`iter::from_fn`] function.
|
||||
/// This `struct` is created by the [`iter::from_fn()`] function.
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`iter::from_fn`]: fn.from_fn.html
|
||||
/// [`iter::from_fn()`]: from_fn
|
||||
#[derive(Clone)]
|
||||
#[stable(feature = "iter_from_fn", since = "1.34.0")]
|
||||
pub struct FromFn<F>(F);
|
||||
@ -601,10 +583,10 @@ where
|
||||
|
||||
/// An new iterator where each successive item is computed based on the preceding one.
|
||||
///
|
||||
/// This `struct` is created by the [`successors`] function.
|
||||
/// This `struct` is created by the [`iter::successors()`] function.
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`successors`]: fn.successors.html
|
||||
/// [`iter::successors()`]: successors
|
||||
#[derive(Clone)]
|
||||
#[stable(feature = "iter_successors", since = "1.34.0")]
|
||||
pub struct Successors<T, F> {
|
||||
|
@ -4,14 +4,13 @@ use crate::ops::{Add, Mul};
|
||||
|
||||
/// Trait to represent types that can be created by summing up an iterator.
|
||||
///
|
||||
/// This trait is used to implement the [`sum`] method on iterators. Types which
|
||||
/// implement the trait can be generated by the [`sum`] method. Like
|
||||
/// This trait is used to implement the [`sum()`] method on iterators. Types which
|
||||
/// implement the trait can be generated by the [`sum()`] method. Like
|
||||
/// [`FromIterator`] this trait should rarely be called directly and instead
|
||||
/// interacted with through [`Iterator::sum`].
|
||||
/// interacted with through [`Iterator::sum()`].
|
||||
///
|
||||
/// [`sum`]: #tymethod.sum
|
||||
/// [`FromIterator`]: crate::iter::FromIterator
|
||||
/// [`Iterator::sum`]: crate::iter::Iterator::sum
|
||||
/// [`sum()`]: Sum::sum
|
||||
/// [`FromIterator`]: iter::FromIterator
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
pub trait Sum<A = Self>: Sized {
|
||||
/// Method which takes an iterator and generates `Self` from the elements by
|
||||
@ -23,14 +22,13 @@ pub trait Sum<A = Self>: Sized {
|
||||
/// Trait to represent types that can be created by multiplying elements of an
|
||||
/// iterator.
|
||||
///
|
||||
/// This trait is used to implement the [`product`] method on iterators. Types
|
||||
/// which implement the trait can be generated by the [`product`] method. Like
|
||||
/// This trait is used to implement the [`product()`] method on iterators. Types
|
||||
/// which implement the trait can be generated by the [`product()`] method. Like
|
||||
/// [`FromIterator`] this trait should rarely be called directly and instead
|
||||
/// interacted with through [`Iterator::product`].
|
||||
/// interacted with through [`Iterator::product()`].
|
||||
///
|
||||
/// [`product`]: #tymethod.product
|
||||
/// [`FromIterator`]: crate::iter::FromIterator
|
||||
/// [`Iterator::product`]: crate::iter::Iterator::product
|
||||
/// [`product()`]: Product::product
|
||||
/// [`FromIterator`]: iter::FromIterator
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
pub trait Product<A = Self>: Sized {
|
||||
/// Method which takes an iterator and generates `Self` from the elements by
|
||||
@ -120,9 +118,9 @@ impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
|
||||
where
|
||||
T: Sum<U>,
|
||||
{
|
||||
/// Takes each element in the `Iterator`: if it is an `Err`, no further
|
||||
/// elements are taken, and the `Err` is returned. Should no `Err` occur,
|
||||
/// the sum of all elements is returned.
|
||||
/// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
|
||||
/// elements are taken, and the [`Err`] is returned. Should no [`Err`]
|
||||
/// occur, the sum of all elements is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -150,9 +148,9 @@ impl<T, U, E> Product<Result<U, E>> for Result<T, E>
|
||||
where
|
||||
T: Product<U>,
|
||||
{
|
||||
/// Takes each element in the `Iterator`: if it is an `Err`, no further
|
||||
/// elements are taken, and the `Err` is returned. Should no `Err` occur,
|
||||
/// the product of all elements is returned.
|
||||
/// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
|
||||
/// elements are taken, and the [`Err`] is returned. Should no [`Err`]
|
||||
/// occur, the product of all elements is returned.
|
||||
fn product<I>(iter: I) -> Result<T, E>
|
||||
where
|
||||
I: Iterator<Item = Result<U, E>>,
|
||||
@ -166,9 +164,9 @@ impl<T, U> Sum<Option<U>> for Option<T>
|
||||
where
|
||||
T: Sum<U>,
|
||||
{
|
||||
/// Takes each element in the `Iterator`: if it is a `None`, no further
|
||||
/// elements are taken, and the `None` is returned. Should no `None` occur,
|
||||
/// the sum of all elements is returned.
|
||||
/// Takes each element in the [`Iterator`]: if it is a [`None`], no further
|
||||
/// elements are taken, and the [`None`] is returned. Should no [`None`]
|
||||
/// occur, the sum of all elements is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -193,9 +191,9 @@ impl<T, U> Product<Option<U>> for Option<T>
|
||||
where
|
||||
T: Product<U>,
|
||||
{
|
||||
/// Takes each element in the `Iterator`: if it is a `None`, no further
|
||||
/// elements are taken, and the `None` is returned. Should no `None` occur,
|
||||
/// the product of all elements is returned.
|
||||
/// Takes each element in the [`Iterator`]: if it is a [`None`], no further
|
||||
/// elements are taken, and the [`None`] is returned. Should no [`None`]
|
||||
/// occur, the product of all elements is returned.
|
||||
fn product<I>(iter: I) -> Option<T>
|
||||
where
|
||||
I: Iterator<Item = Option<U>>,
|
||||
|
@ -1,21 +1,15 @@
|
||||
/// Conversion from an `Iterator`.
|
||||
/// Conversion from an [`Iterator`].
|
||||
///
|
||||
/// By implementing `FromIterator` for a type, you define how it will be
|
||||
/// created from an iterator. This is common for types which describe a
|
||||
/// collection of some kind.
|
||||
///
|
||||
/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead
|
||||
/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s
|
||||
/// [`FromIterator::from_iter()`] is rarely called explicitly, and is instead
|
||||
/// used through [`Iterator::collect()`] method. See [`Iterator::collect()`]'s
|
||||
/// documentation for more examples.
|
||||
///
|
||||
/// [`from_iter`]: #tymethod.from_iter
|
||||
/// [`Iterator`]: trait.Iterator.html
|
||||
/// [`collect`]: trait.Iterator.html#method.collect
|
||||
///
|
||||
/// See also: [`IntoIterator`].
|
||||
///
|
||||
/// [`IntoIterator`]: trait.IntoIterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
@ -30,7 +24,7 @@
|
||||
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
|
||||
/// ```
|
||||
///
|
||||
/// Using [`collect`] to implicitly use `FromIterator`:
|
||||
/// Using [`Iterator::collect()`] to implicitly use `FromIterator`:
|
||||
///
|
||||
/// ```
|
||||
/// let five_fives = std::iter::repeat(5).take(5);
|
||||
@ -119,7 +113,7 @@ pub trait FromIterator<A>: Sized {
|
||||
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
|
||||
}
|
||||
|
||||
/// Conversion into an `Iterator`.
|
||||
/// Conversion into an [`Iterator`].
|
||||
///
|
||||
/// By implementing `IntoIterator` for a type, you define how it will be
|
||||
/// converted to an iterator. This is common for types which describe a
|
||||
@ -130,8 +124,6 @@ pub trait FromIterator<A>: Sized {
|
||||
///
|
||||
/// See also: [`FromIterator`].
|
||||
///
|
||||
/// [`FromIterator`]: trait.FromIterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
@ -326,7 +318,7 @@ pub trait Extend<A> {
|
||||
/// As this is the only required method for this trait, the [trait-level] docs
|
||||
/// contain more details.
|
||||
///
|
||||
/// [trait-level]: trait.Extend.html
|
||||
/// [trait-level]: Extend
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -10,11 +10,12 @@ use crate::ops::{ControlFlow, Try};
|
||||
/// and do not cross: iteration is over when they meet in the middle.
|
||||
///
|
||||
/// In a similar fashion to the [`Iterator`] protocol, once a
|
||||
/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
|
||||
/// may or may not ever return `Some` again. `next()` and `next_back()` are
|
||||
/// interchangeable for this purpose.
|
||||
/// `DoubleEndedIterator` returns [`None`] from a [`next_back()`], calling it
|
||||
/// again may or may not ever return [`Some`] again. [`next()`] and
|
||||
/// [`next_back()`] are interchangeable for this purpose.
|
||||
///
|
||||
/// [`Iterator`]: trait.Iterator.html
|
||||
/// [`next_back()`]: DoubleEndedIterator::next_back
|
||||
/// [`next()`]: Iterator::next
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -42,7 +43,7 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
///
|
||||
/// The [trait-level] docs contain more details.
|
||||
///
|
||||
/// [trait-level]: trait.DoubleEndedIterator.html
|
||||
/// [trait-level]: DoubleEndedIterator
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -66,7 +67,7 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// # Remarks
|
||||
///
|
||||
/// The elements yielded by `DoubleEndedIterator`'s methods may differ from
|
||||
/// the ones yielded by `Iterator`'s methods:
|
||||
/// the ones yielded by [`Iterator`]'s methods:
|
||||
///
|
||||
/// ```
|
||||
/// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')];
|
||||
@ -87,25 +88,23 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// vec![(2, 'b'), (1, 'c')]
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn next_back(&mut self) -> Option<Self::Item>;
|
||||
|
||||
/// Returns the `n`th element from the end of the iterator.
|
||||
///
|
||||
/// This is essentially the reversed version of [`nth`]. Although like most indexing
|
||||
/// operations, the count starts from zero, so `nth_back(0)` returns the first value from
|
||||
/// the end, `nth_back(1)` the second, and so on.
|
||||
/// This is essentially the reversed version of [`Iterator::nth()`].
|
||||
/// Although like most indexing operations, the count starts from zero, so
|
||||
/// `nth_back(0)` returns the first value from the end, `nth_back(1)` the
|
||||
/// second, and so on.
|
||||
///
|
||||
/// Note that all elements between the end and the returned element will be
|
||||
/// consumed, including the returned element. This also means that calling
|
||||
/// `nth_back(0)` multiple times on the same iterator will return different
|
||||
/// elements.
|
||||
///
|
||||
/// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
|
||||
/// iterator.
|
||||
///
|
||||
/// [`nth`]: crate::iter::Iterator::nth
|
||||
/// `nth_back()` will return [`None`] if `n` is greater than or equal to the
|
||||
/// length of the iterator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -145,10 +144,8 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
None
|
||||
}
|
||||
|
||||
/// This is the reverse version of [`try_fold()`]: it takes elements
|
||||
/// starting from the back of the iterator.
|
||||
///
|
||||
/// [`try_fold()`]: Iterator::try_fold
|
||||
/// This is the reverse version of [`Iterator::try_fold()`]: it takes
|
||||
/// elements starting from the back of the iterator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -195,8 +192,8 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// An iterator method that reduces the iterator's elements to a single,
|
||||
/// final value, starting from the back.
|
||||
///
|
||||
/// This is the reverse version of [`fold()`]: it takes elements starting from
|
||||
/// the back of the iterator.
|
||||
/// This is the reverse version of [`Iterator::fold()`]: it takes elements
|
||||
/// starting from the back of the iterator.
|
||||
///
|
||||
/// `rfold()` takes two arguments: an initial value, and a closure with two
|
||||
/// arguments: an 'accumulator', and an element. The closure returns the value that
|
||||
@ -213,8 +210,6 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// Folding is useful whenever you have a collection of something, and want
|
||||
/// to produce a single value from it.
|
||||
///
|
||||
/// [`fold()`]: Iterator::fold
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
@ -6,17 +6,14 @@
|
||||
/// backwards, a good start is to know where the end is.
|
||||
///
|
||||
/// When implementing an `ExactSizeIterator`, you must also implement
|
||||
/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must*
|
||||
/// return the exact size of the iterator.
|
||||
///
|
||||
/// [`Iterator`]: trait.Iterator.html
|
||||
/// [`size_hint`]: trait.Iterator.html#method.size_hint
|
||||
/// [`Iterator`]. When doing so, the implementation of [`Iterator::size_hint`]
|
||||
/// *must* return the exact size of the iterator.
|
||||
///
|
||||
/// The [`len`] method has a default implementation, so you usually shouldn't
|
||||
/// implement it. However, you may be able to provide a more performant
|
||||
/// implementation than the default, so overriding it in this case makes sense.
|
||||
///
|
||||
/// [`len`]: #method.len
|
||||
/// [`len`]: ExactSizeIterator::len
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -72,17 +69,17 @@ pub trait ExactSizeIterator: Iterator {
|
||||
/// Returns the exact length of the iterator.
|
||||
///
|
||||
/// The implementation ensures that the iterator will return exactly `len()`
|
||||
/// more times a `Some(T)` value, before returning `None`.
|
||||
/// more times a [`Some(T)`] value, before returning [`None`].
|
||||
/// This method has a default implementation, so you usually should not
|
||||
/// implement it directly. However, if you can provide a more efficient
|
||||
/// implementation, you can do so. See the [trait-level] docs for an
|
||||
/// example.
|
||||
///
|
||||
/// This function has the same safety guarantees as the [`size_hint`]
|
||||
/// function.
|
||||
/// This function has the same safety guarantees as the
|
||||
/// [`Iterator::size_hint`] function.
|
||||
///
|
||||
/// [trait-level]: trait.ExactSizeIterator.html
|
||||
/// [`size_hint`]: trait.Iterator.html#method.size_hint
|
||||
/// [trait-level]: ExactSizeIterator
|
||||
/// [`Some(T)`]: Some
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -108,8 +105,8 @@ pub trait ExactSizeIterator: Iterator {
|
||||
|
||||
/// Returns `true` if the iterator is empty.
|
||||
///
|
||||
/// This method has a default implementation using `self.len()`, so you
|
||||
/// don't need to implement it yourself.
|
||||
/// This method has a default implementation using
|
||||
/// [`ExactSizeIterator::len()`], so you don't need to implement it yourself.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -2203,7 +2203,6 @@ pub trait Iterator {
|
||||
///
|
||||
/// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`.
|
||||
///
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
@ -2,14 +2,13 @@
|
||||
///
|
||||
/// Calling next on a fused iterator that has returned `None` once is guaranteed
|
||||
/// to return [`None`] again. This trait should be implemented by all iterators
|
||||
/// that behave this way because it allows optimizing [`Iterator::fuse`].
|
||||
/// that behave this way because it allows optimizing [`Iterator::fuse()`].
|
||||
///
|
||||
/// Note: In general, you should not use `FusedIterator` in generic bounds if
|
||||
/// you need a fused iterator. Instead, you should just call [`Iterator::fuse`]
|
||||
/// you need a fused iterator. Instead, you should just call [`Iterator::fuse()`]
|
||||
/// on the iterator. If the iterator is already fused, the additional [`Fuse`]
|
||||
/// wrapper will be a no-op with no performance penalty.
|
||||
///
|
||||
/// [`Iterator::fuse`]: crate::iter::Iterator::fuse
|
||||
/// [`Fuse`]: crate::iter::Fuse
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
@ -24,18 +23,18 @@ impl<I: FusedIterator + ?Sized> FusedIterator for &mut I {}
|
||||
/// (lower bound is equal to upper bound), or the upper bound is [`None`].
|
||||
/// The upper bound must only be [`None`] if the actual iterator length is
|
||||
/// larger than [`usize::MAX`]. In that case, the lower bound must be
|
||||
/// [`usize::MAX`], resulting in a [`.size_hint`] of `(usize::MAX, None)`.
|
||||
/// [`usize::MAX`], resulting in a [`Iterator::size_hint()`] of
|
||||
/// `(usize::MAX, None)`.
|
||||
///
|
||||
/// The iterator must produce exactly the number of elements it reported
|
||||
/// or diverge before reaching the end.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait must only be implemented when the contract is upheld.
|
||||
/// Consumers of this trait must inspect [`.size_hint`]’s upper bound.
|
||||
/// This trait must only be implemented when the contract is upheld. Consumers
|
||||
/// of this trait must inspect [`Iterator::size_hint()`]’s upper bound.
|
||||
///
|
||||
/// [`usize::MAX`]: crate::usize::MAX
|
||||
/// [`.size_hint`]: crate::iter::Iterator::size_hint
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub unsafe trait TrustedLen: Iterator {}
|
||||
@ -46,11 +45,12 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}
|
||||
/// An iterator that when yielding an item will have taken at least one element
|
||||
/// from its underlying [`SourceIter`].
|
||||
///
|
||||
/// Calling next() guarantees that at least one value of the iterator's underlying source
|
||||
/// Calling [`next()`] guarantees that at least one value of the iterator's underlying source
|
||||
/// has been moved out and the result of the iterator chain could be inserted in its place,
|
||||
/// assuming structural constraints of the source allow such an insertion.
|
||||
/// In other words this trait indicates that an iterator pipeline can be collected in place.
|
||||
///
|
||||
/// [`SourceIter`]: ../../std/iter/trait.SourceIter.html
|
||||
/// [`SourceIter`]: crate::iter::SourceIter
|
||||
/// [`next()`]: Iterator::next
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
pub unsafe trait InPlaceIterable: Iterator {}
|
||||
|
@ -175,7 +175,7 @@ impl<T> Option<T> {
|
||||
/// ```
|
||||
#[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"]
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
|
||||
#[rustc_const_stable(feature = "const_option", since = "1.48.0")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const fn is_some(&self) -> bool {
|
||||
matches!(*self, Some(_))
|
||||
@ -195,7 +195,7 @@ impl<T> Option<T> {
|
||||
#[must_use = "if you intended to assert that this doesn't have a value, consider \
|
||||
`.and_then(|| panic!(\"`Option` had a value when expected `None`\"))` instead"]
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
|
||||
#[rustc_const_stable(feature = "const_option", since = "1.48.0")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const fn is_none(&self) -> bool {
|
||||
!self.is_some()
|
||||
@ -254,7 +254,7 @@ impl<T> Option<T> {
|
||||
/// println!("still can print text: {:?}", text);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
|
||||
#[rustc_const_stable(feature = "const_option", since = "1.48.0")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const fn as_ref(&self) -> Option<&T> {
|
||||
match *self {
|
||||
|
@ -838,8 +838,7 @@ impl<T> AtomicPtr<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "atomic_access", since = "1.15.0")]
|
||||
pub fn get_mut(&mut self) -> &mut *mut T {
|
||||
// SAFETY: the mutable reference guarantees unique ownership.
|
||||
unsafe { &mut *self.p.get() }
|
||||
self.p.get_mut()
|
||||
}
|
||||
|
||||
/// Get atomic access to a pointer.
|
||||
@ -1275,8 +1274,7 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5);
|
||||
#[inline]
|
||||
#[$stable_access]
|
||||
pub fn get_mut(&mut self) -> &mut $int_type {
|
||||
// SAFETY: the mutable reference guarantees unique ownership.
|
||||
unsafe { &mut *self.v.get() }
|
||||
self.v.get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,3 +356,19 @@ fn test_replace() {
|
||||
assert_eq!(x, Some(3));
|
||||
assert_eq!(old, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn option_const() {
|
||||
// test that the methods of `Option` are usable in a const context
|
||||
|
||||
const OPTION: Option<usize> = Some(32);
|
||||
|
||||
const REF: Option<&usize> = OPTION.as_ref();
|
||||
assert_eq!(REF, Some(&32));
|
||||
|
||||
const IS_SOME: bool = OPTION.is_some();
|
||||
assert!(IS_SOME);
|
||||
|
||||
const IS_NONE: bool = OPTION.is_none();
|
||||
assert!(!IS_NONE);
|
||||
}
|
||||
|
@ -312,6 +312,7 @@
|
||||
#![feature(try_reserve)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![feature(unsafe_cell_get_mut)]
|
||||
#![feature(unsafe_cell_raw_get)]
|
||||
#![feature(untagged_unions)]
|
||||
#![feature(unwind_attributes)]
|
||||
|
@ -43,11 +43,8 @@ struct BarrierState {
|
||||
generation_id: usize,
|
||||
}
|
||||
|
||||
/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`]
|
||||
/// have rendezvoused.
|
||||
///
|
||||
/// [`wait`]: struct.Barrier.html#method.wait
|
||||
/// [`Barrier`]: struct.Barrier.html
|
||||
/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads
|
||||
/// in the [`Barrier`] have rendezvoused.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -70,10 +67,10 @@ impl fmt::Debug for Barrier {
|
||||
impl Barrier {
|
||||
/// Creates a new barrier that can block a given number of threads.
|
||||
///
|
||||
/// A barrier will block `n`-1 threads which call [`wait`] and then wake up
|
||||
/// all threads at once when the `n`th thread calls [`wait`].
|
||||
/// A barrier will block `n`-1 threads which call [`wait()`] and then wake
|
||||
/// up all threads at once when the `n`th thread calls [`wait()`].
|
||||
///
|
||||
/// [`wait`]: #method.wait
|
||||
/// [`wait()`]: Barrier::wait
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -97,12 +94,9 @@ impl Barrier {
|
||||
/// be used continuously.
|
||||
///
|
||||
/// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
|
||||
/// returns `true` from [`is_leader`] when returning from this function, and
|
||||
/// all other threads will receive a result that will return `false` from
|
||||
/// [`is_leader`].
|
||||
///
|
||||
/// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
|
||||
/// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
|
||||
/// returns `true` from [`BarrierWaitResult::is_leader()`] when returning
|
||||
/// from this function, and all other threads will receive a result that
|
||||
/// will return `false` from [`BarrierWaitResult::is_leader()`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -156,13 +150,12 @@ impl fmt::Debug for BarrierWaitResult {
|
||||
}
|
||||
|
||||
impl BarrierWaitResult {
|
||||
/// Returns `true` if this thread from [`wait`] is the "leader thread".
|
||||
/// Returns `true` if this thread is the "leader thread" for the call to
|
||||
/// [`Barrier::wait()`].
|
||||
///
|
||||
/// Only one thread will have `true` returned from their result, all other
|
||||
/// threads will have `false` returned.
|
||||
///
|
||||
/// [`wait`]: struct.Barrier.html#method.wait
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
@ -406,9 +406,7 @@ impl<T: ?Sized> Mutex<T> {
|
||||
/// ```
|
||||
#[stable(feature = "mutex_get_mut", since = "1.6.0")]
|
||||
pub fn get_mut(&mut self) -> LockResult<&mut T> {
|
||||
// We know statically that there are no other references to `self`, so
|
||||
// there's no need to lock the inner mutex.
|
||||
let data = unsafe { &mut *self.data.get() };
|
||||
let data = self.data.get_mut();
|
||||
poison::map_result(self.poison.borrow(), |_| data)
|
||||
}
|
||||
}
|
||||
|
@ -95,10 +95,7 @@ use crate::thread::{self, Thread};
|
||||
|
||||
/// A synchronization primitive which can be used to run a one-time global
|
||||
/// initialization. Useful for one-time initialization for FFI or related
|
||||
/// functionality. This type can only be constructed with the [`Once::new`]
|
||||
/// constructor.
|
||||
///
|
||||
/// [`Once::new`]: struct.Once.html#method.new
|
||||
/// functionality. This type can only be constructed with [`Once::new()`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -126,11 +123,8 @@ unsafe impl Sync for Once {}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl Send for Once {}
|
||||
|
||||
/// State yielded to [`call_once_force`]’s closure parameter. The state can be
|
||||
/// used to query the poison status of the [`Once`].
|
||||
///
|
||||
/// [`call_once_force`]: struct.Once.html#method.call_once_force
|
||||
/// [`Once`]: struct.Once.html
|
||||
/// State yielded to [`Once::call_once_force()`]’s closure parameter. The state
|
||||
/// can be used to query the poison status of the [`Once`].
|
||||
#[unstable(feature = "once_poison", issue = "33577")]
|
||||
#[derive(Debug)]
|
||||
pub struct OnceState {
|
||||
@ -140,8 +134,6 @@ pub struct OnceState {
|
||||
|
||||
/// Initialization value for static [`Once`] values.
|
||||
///
|
||||
/// [`Once`]: struct.Once.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -212,7 +204,7 @@ impl Once {
|
||||
/// happens-before relation between the closure and code executing after the
|
||||
/// return).
|
||||
///
|
||||
/// If the given closure recursively invokes `call_once` on the same `Once`
|
||||
/// If the given closure recursively invokes `call_once` on the same [`Once`]
|
||||
/// instance the exact behavior is not specified, allowed outcomes are
|
||||
/// a panic or a deadlock.
|
||||
///
|
||||
@ -249,7 +241,7 @@ impl Once {
|
||||
///
|
||||
/// The closure `f` will only be executed once if this is called
|
||||
/// concurrently amongst many threads. If that closure panics, however, then
|
||||
/// it will *poison* this `Once` instance, causing all future invocations of
|
||||
/// it will *poison* this [`Once`] instance, causing all future invocations of
|
||||
/// `call_once` to also panic.
|
||||
///
|
||||
/// This is similar to [poisoning with mutexes][poison].
|
||||
@ -269,21 +261,21 @@ impl Once {
|
||||
self.call_inner(false, &mut |_| f.take().unwrap()());
|
||||
}
|
||||
|
||||
/// Performs the same function as [`call_once`] except ignores poisoning.
|
||||
/// Performs the same function as [`call_once()`] except ignores poisoning.
|
||||
///
|
||||
/// Unlike [`call_once`], if this `Once` has been poisoned (i.e., a previous
|
||||
/// call to `call_once` or `call_once_force` caused a panic), calling
|
||||
/// `call_once_force` will still invoke the closure `f` and will _not_
|
||||
/// result in an immediate panic. If `f` panics, the `Once` will remain
|
||||
/// in a poison state. If `f` does _not_ panic, the `Once` will no
|
||||
/// longer be in a poison state and all future calls to `call_once` or
|
||||
/// `call_once_force` will be no-ops.
|
||||
/// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous
|
||||
/// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling
|
||||
/// [`call_once_force()`] will still invoke the closure `f` and will _not_
|
||||
/// result in an immediate panic. If `f` panics, the [`Once`] will remain
|
||||
/// in a poison state. If `f` does _not_ panic, the [`Once`] will no
|
||||
/// longer be in a poison state and all future calls to [`call_once()`] or
|
||||
/// [`call_once_force()`] will be no-ops.
|
||||
///
|
||||
/// The closure `f` is yielded a [`OnceState`] structure which can be used
|
||||
/// to query the poison status of the `Once`.
|
||||
/// to query the poison status of the [`Once`].
|
||||
///
|
||||
/// [`call_once`]: struct.Once.html#method.call_once
|
||||
/// [`OnceState`]: struct.OnceState.html
|
||||
/// [`call_once()`]: Once::call_once
|
||||
/// [`call_once_force()`]: Once::call_once_force
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -329,18 +321,20 @@ impl Once {
|
||||
self.call_inner(true, &mut |p| f.take().unwrap()(p));
|
||||
}
|
||||
|
||||
/// Returns `true` if some `call_once` call has completed
|
||||
/// Returns `true` if some [`call_once()`] call has completed
|
||||
/// successfully. Specifically, `is_completed` will return false in
|
||||
/// the following situations:
|
||||
/// * `call_once` was not called at all,
|
||||
/// * `call_once` was called, but has not yet completed,
|
||||
/// * the `Once` instance is poisoned
|
||||
/// * [`call_once()`] was not called at all,
|
||||
/// * [`call_once()`] was called, but has not yet completed,
|
||||
/// * the [`Once`] instance is poisoned
|
||||
///
|
||||
/// This function returning `false` does not mean that `Once` has not been
|
||||
/// This function returning `false` does not mean that [`Once`] has not been
|
||||
/// executed. For example, it may have been executed in the time between
|
||||
/// when `is_completed` starts executing and when it returns, in which case
|
||||
/// the `false` return value would be stale (but still permissible).
|
||||
///
|
||||
/// [`call_once()`]: Once::call_once
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -519,14 +513,11 @@ impl Drop for WaiterQueue<'_> {
|
||||
|
||||
impl OnceState {
|
||||
/// Returns `true` if the associated [`Once`] was poisoned prior to the
|
||||
/// invocation of the closure passed to [`call_once_force`].
|
||||
///
|
||||
/// [`call_once_force`]: struct.Once.html#method.call_once_force
|
||||
/// [`Once`]: struct.Once.html
|
||||
/// invocation of the closure passed to [`Once::call_once_force()`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// A poisoned `Once`:
|
||||
/// A poisoned [`Once`]:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(once_poison)]
|
||||
@ -547,7 +538,7 @@ impl OnceState {
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// An unpoisoned `Once`:
|
||||
/// An unpoisoned [`Once`]:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(once_poison)]
|
||||
@ -565,8 +556,6 @@ impl OnceState {
|
||||
}
|
||||
|
||||
/// Poison the associated [`Once`] without explicitly panicking.
|
||||
///
|
||||
/// [`Once`]: struct.Once.html
|
||||
// NOTE: This is currently only exposed for the `lazy` module
|
||||
pub(crate) fn poison(&self) {
|
||||
self.set_state_on_drop_to.set(POISONED);
|
||||
|
@ -404,9 +404,7 @@ impl<T: ?Sized> RwLock<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rwlock_get_mut", since = "1.6.0")]
|
||||
pub fn get_mut(&mut self) -> LockResult<&mut T> {
|
||||
// We know statically that there are no other references to `self`, so
|
||||
// there's no need to lock the inner lock.
|
||||
let data = unsafe { &mut *self.data.get() };
|
||||
let data = self.data.get_mut();
|
||||
poison::map_result(self.poison.borrow(), |_| data)
|
||||
}
|
||||
}
|
||||
|
@ -61,15 +61,15 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
|
||||
let median = bs.ns_iter_summ.median as usize;
|
||||
let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
|
||||
|
||||
output
|
||||
.write_fmt(format_args!(
|
||||
"{:>11} ns/iter (+/- {})",
|
||||
fmt_thousands_sep(median, ','),
|
||||
fmt_thousands_sep(deviation, ',')
|
||||
))
|
||||
.unwrap();
|
||||
write!(
|
||||
output,
|
||||
"{:>11} ns/iter (+/- {})",
|
||||
fmt_thousands_sep(median, ','),
|
||||
fmt_thousands_sep(deviation, ',')
|
||||
)
|
||||
.unwrap();
|
||||
if bs.mb_s != 0 {
|
||||
output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap();
|
||||
write!(output, " = {} MB/s", bs.mb_s).unwrap();
|
||||
}
|
||||
output
|
||||
}
|
||||
@ -83,9 +83,9 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
|
||||
let base = 10_usize.pow(pow);
|
||||
if pow == 0 || trailing || n / base != 0 {
|
||||
if !trailing {
|
||||
output.write_fmt(format_args!("{}", n / base)).unwrap();
|
||||
write!(output, "{}", n / base).unwrap();
|
||||
} else {
|
||||
output.write_fmt(format_args!("{:03}", n / base)).unwrap();
|
||||
write!(output, "{:03}", n / base).unwrap();
|
||||
}
|
||||
if pow != 0 {
|
||||
output.push(sep);
|
||||
@ -98,10 +98,6 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
|
||||
output
|
||||
}
|
||||
|
||||
fn ns_from_dur(dur: Duration) -> u64 {
|
||||
dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64)
|
||||
}
|
||||
|
||||
fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64
|
||||
where
|
||||
F: FnMut() -> T,
|
||||
@ -110,7 +106,7 @@ where
|
||||
for _ in 0..k {
|
||||
black_box(inner());
|
||||
}
|
||||
ns_from_dur(start.elapsed())
|
||||
start.elapsed().as_nanos() as u64
|
||||
}
|
||||
|
||||
pub fn iter<T, F>(inner: &mut F) -> stats::Summary
|
||||
|
@ -49,6 +49,7 @@ lazy_static = "1.3.0"
|
||||
time = "0.1"
|
||||
ignore = "0.4.10"
|
||||
opener = "0.4"
|
||||
merge = "0.1.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.winapi]
|
||||
version = "0.3"
|
||||
|
@ -16,6 +16,7 @@ use crate::flags::Flags;
|
||||
pub use crate::flags::Subcommand;
|
||||
use crate::util::exe;
|
||||
use build_helper::t;
|
||||
use merge::Merge;
|
||||
use serde::Deserialize;
|
||||
|
||||
macro_rules! check_ci_llvm {
|
||||
@ -278,10 +279,31 @@ struct TomlConfig {
|
||||
rust: Option<Rust>,
|
||||
target: Option<HashMap<String, TomlTarget>>,
|
||||
dist: Option<Dist>,
|
||||
profile: Option<String>,
|
||||
}
|
||||
|
||||
impl Merge for TomlConfig {
|
||||
fn merge(&mut self, TomlConfig { build, install, llvm, rust, dist, target, profile: _ }: Self) {
|
||||
fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>) {
|
||||
if let Some(new) = y {
|
||||
if let Some(original) = x {
|
||||
original.merge(new);
|
||||
} else {
|
||||
*x = Some(new);
|
||||
}
|
||||
}
|
||||
};
|
||||
do_merge(&mut self.build, build);
|
||||
do_merge(&mut self.install, install);
|
||||
do_merge(&mut self.llvm, llvm);
|
||||
do_merge(&mut self.rust, rust);
|
||||
do_merge(&mut self.dist, dist);
|
||||
assert!(target.is_none(), "merging target-specific config is not currently supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// TOML representation of various global build decisions.
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct Build {
|
||||
build: Option<String>,
|
||||
@ -321,7 +343,7 @@ struct Build {
|
||||
}
|
||||
|
||||
/// TOML representation of various global install decisions.
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct Install {
|
||||
prefix: Option<String>,
|
||||
@ -338,7 +360,7 @@ struct Install {
|
||||
}
|
||||
|
||||
/// TOML representation of how the LLVM build is configured.
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct Llvm {
|
||||
skip_rebuild: Option<bool>,
|
||||
@ -365,7 +387,7 @@ struct Llvm {
|
||||
download_ci_llvm: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct Dist {
|
||||
sign_folder: Option<String>,
|
||||
@ -389,7 +411,7 @@ impl Default for StringOrBool {
|
||||
}
|
||||
|
||||
/// TOML representation of how the Rust build is configured.
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct Rust {
|
||||
optimize: Option<bool>,
|
||||
@ -434,7 +456,7 @@ struct Rust {
|
||||
}
|
||||
|
||||
/// TOML representation of how each build target is configured.
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, Merge)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct TomlTarget {
|
||||
cc: Option<String>,
|
||||
@ -524,27 +546,31 @@ impl Config {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
let toml = TomlConfig::default();
|
||||
let get_toml = |_| TomlConfig::default();
|
||||
#[cfg(not(test))]
|
||||
let toml = flags
|
||||
.config
|
||||
.map(|file| {
|
||||
use std::process;
|
||||
let get_toml = |file: PathBuf| {
|
||||
use std::process;
|
||||
|
||||
let contents = t!(fs::read_to_string(&file));
|
||||
match toml::from_str(&contents) {
|
||||
Ok(table) => table,
|
||||
Err(err) => {
|
||||
println!(
|
||||
"failed to parse TOML configuration '{}': {}",
|
||||
file.display(),
|
||||
err
|
||||
);
|
||||
process::exit(2);
|
||||
}
|
||||
let contents = t!(fs::read_to_string(&file), "configuration file did not exist");
|
||||
match toml::from_str(&contents) {
|
||||
Ok(table) => table,
|
||||
Err(err) => {
|
||||
println!("failed to parse TOML configuration '{}': {}", file.display(), err);
|
||||
process::exit(2);
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(TomlConfig::default);
|
||||
}
|
||||
};
|
||||
|
||||
let mut toml = flags.config.map(get_toml).unwrap_or_else(TomlConfig::default);
|
||||
if let Some(include) = &toml.profile {
|
||||
let mut include_path = config.src.clone();
|
||||
include_path.push("src");
|
||||
include_path.push("bootstrap");
|
||||
include_path.push("defaults");
|
||||
include_path.push(format!("config.toml.{}", include));
|
||||
let included_toml = get_toml(include_path);
|
||||
toml.merge(included_toml);
|
||||
}
|
||||
|
||||
let build = toml.build.unwrap_or_default();
|
||||
|
||||
|
11
src/bootstrap/defaults/README.md
Normal file
11
src/bootstrap/defaults/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# About bootstrap defaults
|
||||
|
||||
These defaults are intended to be a good starting point for working with x.py,
|
||||
with the understanding that no one set of defaults make sense for everyone.
|
||||
|
||||
They are still experimental, and we'd appreciate your help improving them!
|
||||
If you use a setting that's not in these defaults that you think others would benefit from, please [file an issue] or make a PR with the changes.
|
||||
Similarly, if one of these defaults doesn't match what you use personally,
|
||||
please open an issue to get it changed.
|
||||
|
||||
[file an issue]: https://github.com/rust-lang/rust/issues/new/choose
|
13
src/bootstrap/defaults/config.toml.codegen
Normal file
13
src/bootstrap/defaults/config.toml.codegen
Normal file
@ -0,0 +1,13 @@
|
||||
# These defaults are meant for contributors to the compiler who modify codegen or LLVM
|
||||
[llvm]
|
||||
# This enables debug-assertions in LLVM,
|
||||
# catching logic errors in codegen much earlier in the process.
|
||||
assertions = true
|
||||
|
||||
[rust]
|
||||
# This enables `RUSTC_LOG=debug`, avoiding confusing situations
|
||||
# where adding `debug!()` appears to do nothing.
|
||||
# However, it makes running the compiler slightly slower.
|
||||
debug-logging = true
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
incremental = true
|
8
src/bootstrap/defaults/config.toml.compiler
Normal file
8
src/bootstrap/defaults/config.toml.compiler
Normal file
@ -0,0 +1,8 @@
|
||||
# These defaults are meant for contributors to the compiler who do not modify codegen or LLVM
|
||||
[rust]
|
||||
# This enables `RUSTC_LOG=debug`, avoiding confusing situations
|
||||
# where adding `debug!()` appears to do nothing.
|
||||
# However, it makes running the compiler slightly slower.
|
||||
debug-logging = true
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
incremental = true
|
10
src/bootstrap/defaults/config.toml.library
Normal file
10
src/bootstrap/defaults/config.toml.library
Normal file
@ -0,0 +1,10 @@
|
||||
# These defaults are meant for contributors to the standard library and documentation.
|
||||
[build]
|
||||
# When building the standard library, you almost never want to build the compiler itself.
|
||||
build-stage = 0
|
||||
test-stage = 0
|
||||
bench-stage = 0
|
||||
|
||||
[rust]
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
incremental = true
|
9
src/bootstrap/defaults/config.toml.user
Normal file
9
src/bootstrap/defaults/config.toml.user
Normal file
@ -0,0 +1,9 @@
|
||||
# These defaults are meant for users and distro maintainers building from source, without intending to make multiple changes.
|
||||
[build]
|
||||
# When compiling from source, you almost always want a full stage 2 build,
|
||||
# which has all the latest optimizations from nightly.
|
||||
build-stage = 2
|
||||
test-stage = 2
|
||||
doc-stage = 2
|
||||
# When compiling from source, you usually want all tools.
|
||||
extended = true
|
16
src/test/codegen/issue-34634.rs
Normal file
16
src/test/codegen/issue-34634.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// Test that `wrapping_div` only checks divisor once.
|
||||
// This test checks that there is only a single compare agains -1 and -1 is not present as a
|
||||
// switch case (the second check present until rustc 1.12).
|
||||
// This test also verifies that a single panic call is generated (for the division by zero case).
|
||||
|
||||
// compile-flags: -O
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// CHECK-LABEL: @f
|
||||
#[no_mangle]
|
||||
pub fn f(x: i32, y: i32) -> i32 {
|
||||
// CHECK-COUNT-1: icmp eq i32 %y, -1
|
||||
// CHECK-COUNT-1: panic
|
||||
// CHECK-NOT: i32 -1, label
|
||||
x.wrapping_div(y)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(const_option)]
|
||||
|
||||
const X: Option<i32> = Some(32);
|
||||
const Y: Option<&i32> = X.as_ref();
|
||||
|
||||
const IS_SOME: bool = X.is_some();
|
||||
const IS_NONE: bool = Y.is_none();
|
||||
|
||||
fn main() {
|
||||
assert!(IS_SOME);
|
||||
assert!(!IS_NONE)
|
||||
}
|
@ -1440,15 +1440,12 @@ where
|
||||
|
||||
mod redundant_pattern_match {
|
||||
use super::REDUNDANT_PATTERN_MATCHING;
|
||||
use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
|
||||
use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_mir::const_eval::is_const_fn;
|
||||
use rustc_span::source_map::Symbol;
|
||||
|
||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
|
||||
@ -1468,37 +1465,24 @@ mod redundant_pattern_match {
|
||||
arms: &[Arm<'_>],
|
||||
keyword: &'static str,
|
||||
) {
|
||||
fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
|
||||
if match_qpath(path, &paths::RESULT_OK) {
|
||||
return Some("is_ok()");
|
||||
}
|
||||
if match_qpath(path, &paths::RESULT_ERR) {
|
||||
return Some("is_err()");
|
||||
}
|
||||
if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
|
||||
return Some("is_some()");
|
||||
}
|
||||
if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
|
||||
return Some("is_none()");
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
let hir_id = expr.hir_id;
|
||||
let good_method = match arms[0].pat.kind {
|
||||
PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
|
||||
if let PatKind::Wild = patterns[0].kind {
|
||||
find_suggestion(cx, hir_id, path)
|
||||
if match_qpath(path, &paths::RESULT_OK) {
|
||||
"is_ok()"
|
||||
} else if match_qpath(path, &paths::RESULT_ERR) {
|
||||
"is_err()"
|
||||
} else if match_qpath(path, &paths::OPTION_SOME) {
|
||||
"is_some()"
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
None
|
||||
return;
|
||||
}
|
||||
},
|
||||
PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
|
||||
_ => None,
|
||||
};
|
||||
let good_method = match good_method {
|
||||
Some(method) => method,
|
||||
None => return,
|
||||
PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// check that `while_let_on_iterator` lint does not trigger
|
||||
@ -1547,7 +1531,6 @@ mod redundant_pattern_match {
|
||||
if arms.len() == 2 {
|
||||
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
|
||||
|
||||
let hir_id = expr.hir_id;
|
||||
let found_good_method = match node_pair {
|
||||
(
|
||||
PatKind::TupleStruct(ref path_left, ref patterns_left, _),
|
||||
@ -1562,8 +1545,6 @@ mod redundant_pattern_match {
|
||||
&paths::RESULT_ERR,
|
||||
"is_ok()",
|
||||
"is_err()",
|
||||
|| true,
|
||||
|| true,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -1582,8 +1563,6 @@ mod redundant_pattern_match {
|
||||
&paths::OPTION_NONE,
|
||||
"is_some()",
|
||||
"is_none()",
|
||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_some"),
|
||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_none"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -1616,7 +1595,6 @@ mod redundant_pattern_match {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn find_good_method_for_match<'a>(
|
||||
arms: &[Arm<'_>],
|
||||
path_left: &QPath<'_>,
|
||||
@ -1625,8 +1603,6 @@ mod redundant_pattern_match {
|
||||
expected_right: &[&str],
|
||||
should_be_left: &'a str,
|
||||
should_be_right: &'a str,
|
||||
can_suggest_left: impl Fn() -> bool,
|
||||
can_suggest_right: impl Fn() -> bool,
|
||||
) -> Option<&'a str> {
|
||||
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
|
||||
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
||||
@ -1638,35 +1614,13 @@ mod redundant_pattern_match {
|
||||
|
||||
match body_node_pair {
|
||||
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
|
||||
(LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
|
||||
(LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
|
||||
(LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
|
||||
(LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
|
||||
if !in_constant(cx, hir_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
|
||||
cx.tcx
|
||||
.get_diagnostic_item(diag_item)
|
||||
.and_then(|def_id| {
|
||||
cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
|
||||
cx.tcx
|
||||
.associated_items(*imp)
|
||||
.in_definition_order()
|
||||
.find_map(|item| match item.kind {
|
||||
ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
})
|
||||
.map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -76,7 +76,6 @@ fn main() {
|
||||
takes_bool(x);
|
||||
|
||||
issue5504();
|
||||
issue5697();
|
||||
issue6067();
|
||||
|
||||
let _ = if gen_opt().is_some() {
|
||||
@ -129,41 +128,31 @@ fn issue5504() {
|
||||
while m!().is_some() {}
|
||||
}
|
||||
|
||||
// None of these should be linted because none of the suggested methods
|
||||
// are `const fn` without toggling a feature.
|
||||
const fn issue5697() {
|
||||
if let Some(_) = Some(42) {}
|
||||
|
||||
if let None = None::<()> {}
|
||||
|
||||
while let Some(_) = Some(42) {}
|
||||
|
||||
while let None = None::<()> {}
|
||||
|
||||
match Some(42) {
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
|
||||
match None::<()> {
|
||||
Some(_) => false,
|
||||
None => true,
|
||||
};
|
||||
}
|
||||
|
||||
// Methods that are unstable const should not be suggested within a const context, see issue #5697.
|
||||
// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
|
||||
// so the following should be linted.
|
||||
// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none`
|
||||
// of `Option` were stabilized as const, so the following should be linted.
|
||||
const fn issue6067() {
|
||||
if Ok::<i32, i32>(42).is_ok() {}
|
||||
|
||||
if Err::<i32, i32>(42).is_err() {}
|
||||
|
||||
if Some(42).is_some() {}
|
||||
|
||||
if None::<()>.is_none() {}
|
||||
|
||||
while Ok::<i32, i32>(10).is_ok() {}
|
||||
|
||||
while Ok::<i32, i32>(10).is_err() {}
|
||||
|
||||
while Some(42).is_some() {}
|
||||
|
||||
while None::<()>.is_none() {}
|
||||
|
||||
Ok::<i32, i32>(42).is_ok();
|
||||
|
||||
Err::<i32, i32>(42).is_err();
|
||||
|
||||
Some(42).is_some();
|
||||
|
||||
None::<()>.is_none();
|
||||
}
|
||||
|
@ -97,7 +97,6 @@ fn main() {
|
||||
takes_bool(x);
|
||||
|
||||
issue5504();
|
||||
issue5697();
|
||||
issue6067();
|
||||
|
||||
let _ = if let Some(_) = gen_opt() {
|
||||
@ -150,17 +149,36 @@ fn issue5504() {
|
||||
while let Some(_) = m!() {}
|
||||
}
|
||||
|
||||
// None of these should be linted because none of the suggested methods
|
||||
// are `const fn` without toggling a feature.
|
||||
const fn issue5697() {
|
||||
// Methods that are unstable const should not be suggested within a const context, see issue #5697.
|
||||
// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result`, and `is_some` and `is_none`
|
||||
// of `Option` were stabilized as const, so the following should be linted.
|
||||
const fn issue6067() {
|
||||
if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
|
||||
if let Err(_) = Err::<i32, i32>(42) {}
|
||||
|
||||
if let Some(_) = Some(42) {}
|
||||
|
||||
if let None = None::<()> {}
|
||||
|
||||
while let Ok(_) = Ok::<i32, i32>(10) {}
|
||||
|
||||
while let Err(_) = Ok::<i32, i32>(10) {}
|
||||
|
||||
while let Some(_) = Some(42) {}
|
||||
|
||||
while let None = None::<()> {}
|
||||
|
||||
match Ok::<i32, i32>(42) {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
};
|
||||
|
||||
match Err::<i32, i32>(42) {
|
||||
Ok(_) => false,
|
||||
Err(_) => true,
|
||||
};
|
||||
|
||||
match Some(42) {
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
@ -171,26 +189,3 @@ const fn issue5697() {
|
||||
None => true,
|
||||
};
|
||||
}
|
||||
|
||||
// Methods that are unstable const should not be suggested within a const context, see issue #5697.
|
||||
// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
|
||||
// so the following should be linted.
|
||||
const fn issue6067() {
|
||||
if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
|
||||
if let Err(_) = Err::<i32, i32>(42) {}
|
||||
|
||||
while let Ok(_) = Ok::<i32, i32>(10) {}
|
||||
|
||||
while let Err(_) = Ok::<i32, i32>(10) {}
|
||||
|
||||
match Ok::<i32, i32>(42) {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
};
|
||||
|
||||
match Err::<i32, i32>(42) {
|
||||
Ok(_) => false,
|
||||
Err(_) => true,
|
||||
};
|
||||
}
|
||||
|
@ -149,79 +149,103 @@ LL | let x = if let Some(_) = opt { true } else { false };
|
||||
| -------^^^^^^^------ help: try this: `if opt.is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:103:20
|
||||
--> $DIR/redundant_pattern_matching.rs:102:20
|
||||
|
|
||||
LL | let _ = if let Some(_) = gen_opt() {
|
||||
| -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:105:19
|
||||
--> $DIR/redundant_pattern_matching.rs:104:19
|
||||
|
|
||||
LL | } else if let None = gen_opt() {
|
||||
| -------^^^^------------ help: try this: `if gen_opt().is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:107:19
|
||||
--> $DIR/redundant_pattern_matching.rs:106:19
|
||||
|
|
||||
LL | } else if let Ok(_) = gen_res() {
|
||||
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:109:19
|
||||
--> $DIR/redundant_pattern_matching.rs:108:19
|
||||
|
|
||||
LL | } else if let Err(_) = gen_res() {
|
||||
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:142:19
|
||||
--> $DIR/redundant_pattern_matching.rs:141:19
|
||||
|
|
||||
LL | while let Some(_) = r#try!(result_opt()) {}
|
||||
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:143:16
|
||||
--> $DIR/redundant_pattern_matching.rs:142:16
|
||||
|
|
||||
LL | if let Some(_) = r#try!(result_opt()) {}
|
||||
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:149:12
|
||||
--> $DIR/redundant_pattern_matching.rs:148:12
|
||||
|
|
||||
LL | if let Some(_) = m!() {}
|
||||
| -------^^^^^^^------- help: try this: `if m!().is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:150:15
|
||||
--> $DIR/redundant_pattern_matching.rs:149:15
|
||||
|
|
||||
LL | while let Some(_) = m!() {}
|
||||
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:179:12
|
||||
--> $DIR/redundant_pattern_matching.rs:156:12
|
||||
|
|
||||
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:181:12
|
||||
--> $DIR/redundant_pattern_matching.rs:158:12
|
||||
|
|
||||
LL | if let Err(_) = Err::<i32, i32>(42) {}
|
||||
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:160:12
|
||||
|
|
||||
LL | if let Some(_) = Some(42) {}
|
||||
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:162:12
|
||||
|
|
||||
LL | if let None = None::<()> {}
|
||||
| -------^^^^------------- help: try this: `if None::<()>.is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:183:15
|
||||
--> $DIR/redundant_pattern_matching.rs:164:15
|
||||
|
|
||||
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
|
||||
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:185:15
|
||||
--> $DIR/redundant_pattern_matching.rs:166:15
|
||||
|
|
||||
LL | while let Err(_) = Ok::<i32, i32>(10) {}
|
||||
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:168:15
|
||||
|
|
||||
LL | while let Some(_) = Some(42) {}
|
||||
| ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:170:15
|
||||
|
|
||||
LL | while let None = None::<()> {}
|
||||
| ----------^^^^------------- help: try this: `while None::<()>.is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:187:5
|
||||
--> $DIR/redundant_pattern_matching.rs:172:5
|
||||
|
|
||||
LL | / match Ok::<i32, i32>(42) {
|
||||
LL | | Ok(_) => true,
|
||||
@ -230,7 +254,7 @@ LL | | };
|
||||
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:192:5
|
||||
--> $DIR/redundant_pattern_matching.rs:177:5
|
||||
|
|
||||
LL | / match Err::<i32, i32>(42) {
|
||||
LL | | Ok(_) => false,
|
||||
@ -238,5 +262,23 @@ LL | | Err(_) => true,
|
||||
LL | | };
|
||||
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
|
||||
|
||||
error: aborting due to 35 previous errors
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:182:5
|
||||
|
|
||||
LL | / match Some(42) {
|
||||
LL | | Some(_) => true,
|
||||
LL | | None => false,
|
||||
LL | | };
|
||||
| |_____^ help: try this: `Some(42).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:187:5
|
||||
|
|
||||
LL | / match None::<()> {
|
||||
LL | | Some(_) => false,
|
||||
LL | | None => true,
|
||||
LL | | };
|
||||
| |_____^ help: try this: `None::<()>.is_none()`
|
||||
|
||||
error: aborting due to 41 previous errors
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 5a15c8a6dd62033f69688f9d1c6eacd674158539
|
||||
Subproject commit cbc7560ae2d44669ef6ba0f43014e10ce881180e
|
@ -27,12 +27,12 @@ macro_rules! t {
|
||||
|
||||
fn generate_stub_issue(path: &Path, name: &str, issue: u32) {
|
||||
let mut file = t!(File::create(path));
|
||||
t!(file.write_fmt(format_args!(include_str!("stub-issue.md"), name = name, issue = issue)));
|
||||
t!(write!(file, include_str!("stub-issue.md"), name = name, issue = issue));
|
||||
}
|
||||
|
||||
fn generate_stub_no_issue(path: &Path, name: &str) {
|
||||
let mut file = t!(File::create(path));
|
||||
t!(file.write_fmt(format_args!(include_str!("stub-no-issue.md"), name = name)));
|
||||
t!(write!(file, include_str!("stub-no-issue.md"), name = name));
|
||||
}
|
||||
|
||||
fn set_to_summary_str(set: &BTreeSet<String>, dir: &str) -> String {
|
||||
|
Loading…
x
Reference in New Issue
Block a user