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:
bors 2020-09-21 10:26:59 +00:00
commit 956e06c6c8
46 changed files with 594 additions and 506 deletions

View File

@ -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"

View File

@ -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);

View File

@ -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());
}

View File

@ -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> {

View File

@ -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 theres 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 theres 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 theres 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 users 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 }

View File

@ -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);

View File

@ -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 theres 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 theres 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 theres 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 users 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(

View File

@ -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>;
}

View File

@ -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>

View File

@ -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 {

View File

@ -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

View File

@ -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)],

View File

@ -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);
}
}
}
}

View File

@ -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
# =============================================================================

View File

@ -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.

View File

@ -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 doesnt 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> {

View File

@ -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>>,

View File

@ -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
///

View File

@ -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:

View File

@ -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
///

View File

@ -2203,7 +2203,6 @@ pub trait Iterator {
///
/// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`.
///
///
/// # Examples
///
/// ```

View File

@ -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 {}

View File

@ -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 {

View File

@ -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()
}
}

View File

@ -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);
}

View File

@ -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)]

View File

@ -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
///
/// ```

View File

@ -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)
}
}

View File

@ -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);

View File

@ -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)
}
}

View File

@ -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

View File

@ -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"

View File

@ -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();

View 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

View 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

View 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

View 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

View 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

View 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)
}

View File

@ -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)
}

View File

@ -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]

View File

@ -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();
}

View File

@ -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,
};
}

View File

@ -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

View File

@ -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 {