name: Library Tracking Issue
about: A tracking issue for an unstable library feature.
title: Tracking Issue for XXX
-labels: C-tracking-issue T-libs
+labels: C-tracking-issue, T-libs
---
<!--
Thank you for creating a tracking issue!
[[package]]
name = "curl"
-version = "0.4.31"
+version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9447ad28eee2a5cfb031c329d46bef77487244fff6a724b378885b8691a35f78"
+checksum = "e268162af1a5fe89917ae25ba3b0a77c8da752bdc58e7dbb4f15b91fbd33756e"
dependencies = [
"curl-sys",
"libc",
[[package]]
name = "curl-sys"
-version = "0.4.34+curl-7.71.1"
+version = "0.4.39+curl-7.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad4eff0be6985b7e709f64b5a541f700e9ad1407190a29f4884319eb663ed1d6"
+checksum = "07a8ce861e7b68a0b394e814d7ee9f1b2750ff8bd10372c6ad3bacc10e86f874"
dependencies = [
"cc",
"libc",
[[package]]
name = "git2"
-version = "0.13.12"
+version = "0.13.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224"
+checksum = "186dd99cc77576e58344ad614fa9bb27bad9d048f85de3ca850c1f4e8b048260"
dependencies = [
"bitflags",
"libc",
[[package]]
name = "git2-curl"
-version = "0.14.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "502d532a2d06184beb3bc869d4d90236e60934e3382c921b203fa3c33e212bd7"
+checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50"
dependencies = [
"curl",
"git2",
[[package]]
name = "libgit2-sys"
-version = "0.12.14+1.1.0"
+version = "0.12.16+1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549"
+checksum = "9f91b2f931ee975a98155195be8cd82d02e8e029d7d793d2bac1b8181ac97020"
dependencies = [
"cc",
"libc",
"byteorder",
"crossbeam-utils 0.7.2",
"libc",
+ "libz-sys",
"proc-macro2",
"quote",
"serde",
[[package]]
name = "rustfmt-nightly"
-version = "1.4.29"
+version = "1.4.30"
dependencies = [
"annotate-snippets 0.6.1",
"anyhow",
"chrono",
"lazy_static",
"matchers",
- "parking_lot 0.11.0",
+ "parking_lot 0.9.0",
"regex",
"serde",
"serde_json",
+Version 1.49.0 (2020-12-31)
+============================
+
+Language
+-----------------------
+
+- [Unions can now implement `Drop`, and you can now have a field in a union
+ with `ManuallyDrop<T>`.][77547]
+- [You can now cast uninhabited enums to integers.][76199]
+- [You can now bind by reference and by move in patterns.][76119] This
+ allows you to selectively borrow individual components of a type. E.g.
+ ```rust
+ #[derive(Debug)]
+ struct Person {
+ name: String,
+ age: u8,
+ }
+
+ let person = Person {
+ name: String::from("Alice"),
+ age: 20,
+ };
+
+ // `name` is moved out of person, but `age` is referenced.
+ let Person { name, ref age } = person;
+ println!("{} {}", name, age);
+ ```
+
+Compiler
+-----------------------
+
+- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228]
+- [Added tier 2 support for `aarch64-apple-darwin`.][75991]
+- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914]
+- [Added tier 3 support for `mipsel-unknown-none`.][78676]
+- [Raised the minimum supported LLVM version to LLVM 9.][78848]
+- [Output from threads spawned in tests is now captured.][78227]
+- [Change os and vendor values to "none" and "unknown" for some targets][78951]
+
+\* Refer to Rust's [platform support page][forge-platform-support] for more
+information on Rust's tiered platform support.
+
+Libraries
+-----------------------
+
+- [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109]
+- [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997]
+- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989]
+
+Stabilized APIs
+---------------
+
+- [`slice::select_nth_unstable`]
+- [`slice::select_nth_unstable_by`]
+- [`slice::select_nth_unstable_by_key`]
+
+The following previously stable methods are now `const`.
+
+- [`Poll::is_ready`]
+- [`Poll::is_pending`]
+
+Cargo
+-----------------------
+- [Building a crate with `cargo-package` should now be independently reproducible.][cargo/8864]
+- [`cargo-tree` now marks proc-macro crates.][cargo/8765]
+- [Added `CARGO_PRIMARY_PACKAGE` build-time environment variable.][cargo/8758] This
+ variable will be set if the crate being built is one the user selected to build, either
+ with `-p` or through defaults.
+- [You can now use glob patterns when specifying packages & targets.][cargo/8752]
+
+
+Compatibility Notes
+-------------------
+
+- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier 2 support.][78746]
+- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376]
+- [Rustc will now check for the validity of some built-in attributes on enum variants.][77015]
+ Previously such invalid or unused attributes could be ignored.
+- Leading whitespace is stripped more uniformly in documentation comments, which may change behavior. You
+ read [this post about the changes][rustdoc-ws-post] for more details.
+- [Trait bounds are no longer inferred for associated types.][79904]
+
+Internal Only
+-------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc and
+related tools.
+
+- [rustc's internal crates are now compiled using the `initial-exec` Thread
+ Local Storage model.][78201]
+- [Calculate visibilities once in resolve.][78077]
+- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703]
+- [Added `--color` for configuring terminal color support to bootstrap.][79004]
+
+
+[75991]: https://github.com/rust-lang/rust/pull/75991
+[78951]: https://github.com/rust-lang/rust/pull/78951
+[78848]: https://github.com/rust-lang/rust/pull/78848
+[78746]: https://github.com/rust-lang/rust/pull/78746
+[78376]: https://github.com/rust-lang/rust/pull/78376
+[78228]: https://github.com/rust-lang/rust/pull/78228
+[78227]: https://github.com/rust-lang/rust/pull/78227
+[78201]: https://github.com/rust-lang/rust/pull/78201
+[78109]: https://github.com/rust-lang/rust/pull/78109
+[78077]: https://github.com/rust-lang/rust/pull/78077
+[77997]: https://github.com/rust-lang/rust/pull/77997
+[77703]: https://github.com/rust-lang/rust/pull/77703
+[77547]: https://github.com/rust-lang/rust/pull/77547
+[77015]: https://github.com/rust-lang/rust/pull/77015
+[76199]: https://github.com/rust-lang/rust/pull/76199
+[76119]: https://github.com/rust-lang/rust/pull/76119
+[75914]: https://github.com/rust-lang/rust/pull/75914
+[74989]: https://github.com/rust-lang/rust/pull/74989
+[79004]: https://github.com/rust-lang/rust/pull/79004
+[78676]: https://github.com/rust-lang/rust/pull/78676
+[79904]: https://github.com/rust-lang/rust/issues/79904
+[cargo/8864]: https://github.com/rust-lang/cargo/pull/8864
+[cargo/8765]: https://github.com/rust-lang/cargo/pull/8765
+[cargo/8758]: https://github.com/rust-lang/cargo/pull/8758
+[cargo/8752]: https://github.com/rust-lang/cargo/pull/8752
+[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable
+[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by
+[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key
+[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html
+[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready
+[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending
+[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc
+
Version 1.48.0 (2020-11-19)
==========================
Compiler
--------
- [Stabilised the `-C link-self-contained=<yes|no>` compiler flag.][76158] This tells
- `rustc` whether to link its own C runtime and libraries or to rely on a external
+ `rustc` whether to link its own C runtime and libraries or to rely on a external
linker to find them. (Supported only on `windows-gnu`, `linux-musl`, and `wasi` platforms.)
- [You can now use `-C target-feature=+crt-static` on `linux-gnu` targets.][77386]
Note: If you're using cargo you must explicitly pass the `--target` flag.
- [Foreign exceptions are now caught by `catch_unwind` and will cause an abort.][70212]
Note: This behaviour is not guaranteed and is still considered undefined behaviour,
see the [`catch_unwind`] documentation for further information.
-
+
Internal Only
[76030]: https://github.com/rust-lang/rust/pull/76030/
[70212]: https://github.com/rust-lang/rust/pull/70212/
[27675]: https://github.com/rust-lang/rust/issues/27675/
-[54121]: https://github.com/rust-lang/rust/issues/54121/
+[54121]: https://github.com/rust-lang/rust/issues/54121/
[71274]: https://github.com/rust-lang/rust/pull/71274/
[77386]: https://github.com/rust-lang/rust/pull/77386/
[77153]: https://github.com/rust-lang/rust/pull/77153/
#![feature(new_uninit)]
#![feature(maybe_uninit_slice)]
#![feature(array_value_iter)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
#![feature(min_specialization)]
#![cfg_attr(test, feature(test))]
impl GenericArgs {
pub fn is_angle_bracketed(&self) -> bool {
- match *self {
- AngleBracketed(..) => true,
- _ => false,
- }
+ matches!(self, AngleBracketed(..))
}
pub fn span(&self) -> Span {
/// Is this a `..` pattern?
pub fn is_rest(&self) -> bool {
- match self.kind {
- PatKind::Rest => true,
- _ => false,
- }
+ matches!(self.kind, PatKind::Rest)
}
}
-/// A single field in a struct pattern
+/// A single field in a struct pattern.
///
-/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
-/// are treated the same as` x: x, y: ref y, z: ref mut z`,
-/// except is_shorthand is true
+/// Patterns like the fields of `Foo { x, ref y, ref mut z }`
+/// are treated the same as `x: x, y: ref y, z: ref mut z`,
+/// except when `is_shorthand` is true.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct FieldPat {
- /// The identifier for the field
+ /// The identifier for the field.
pub ident: Ident,
- /// The pattern the field is destructured to
+ /// The pattern the field is destructured to.
pub pat: P<Pat>,
pub is_shorthand: bool,
pub attrs: AttrVec,
}
}
pub fn lazy(&self) -> bool {
- match *self {
- BinOpKind::And | BinOpKind::Or => true,
- _ => false,
- }
+ matches!(self, BinOpKind::And | BinOpKind::Or)
}
pub fn is_comparison(&self) -> bool {
}
pub fn is_item(&self) -> bool {
- match self.kind {
- StmtKind::Item(_) => true,
- _ => false,
- }
+ matches!(self.kind, StmtKind::Item(_))
}
pub fn is_expr(&self) -> bool {
- match self.kind {
- StmtKind::Expr(_) => true,
- _ => false,
- }
+ matches!(self.kind, StmtKind::Expr(_))
}
}
if let ExprKind::Block(ref block, _) = self.kind {
match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
// Implicit return
- Some(&StmtKind::Expr(_)) => true,
- Some(&StmtKind::Semi(ref expr)) => {
- if let ExprKind::Ret(_) = expr.kind {
- // Last statement is explicit return.
- true
- } else {
- false
- }
- }
+ Some(StmtKind::Expr(_)) => true,
+ // Last statement is an explicit return?
+ Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)),
// This is a block that doesn't end in either an implicit or explicit return.
_ => false,
}
/// Is this expr either `N`, or `{ N }`.
///
/// If this is not the case, name resolution does not resolve `N` when using
- /// `feature(min_const_generics)` as more complex expressions are not supported.
+ /// `min_const_generics` as more complex expressions are not supported.
pub fn is_potential_trivial_const_param(&self) -> bool {
let this = if let ExprKind::Block(ref block, None) = self.kind {
if block.stmts.len() == 1 {
impl LitKind {
/// Returns `true` if this literal is a string.
pub fn is_str(&self) -> bool {
- match *self {
- LitKind::Str(..) => true,
- _ => false,
- }
+ matches!(self, LitKind::Str(..))
}
/// Returns `true` if this literal is byte literal string.
pub fn is_bytestr(&self) -> bool {
- match self {
- LitKind::ByteStr(_) => true,
- _ => false,
- }
+ matches!(self, LitKind::ByteStr(_))
}
/// Returns `true` if this is a numeric literal.
pub fn is_numeric(&self) -> bool {
- match *self {
- LitKind::Int(..) | LitKind::Float(..) => true,
- _ => false,
- }
+ matches!(self, LitKind::Int(..) | LitKind::Float(..))
}
/// Returns `true` if this literal has no suffix.
}
pub fn is_unit(&self) -> bool {
- if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false }
+ matches!(self, TyKind::Tup(tys) if tys.is_empty())
}
}
self.inputs.get(0).map_or(false, Param::is_self)
}
pub fn c_variadic(&self) -> bool {
- self.inputs.last().map_or(false, |arg| match arg.ty.kind {
- TyKind::CVarArgs => true,
- _ => false,
- })
+ self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs))
}
}
}
pub fn is_word(&self) -> bool {
- match self.kind {
- MetaItemKind::Word => true,
- _ => false,
- }
+ matches!(self.kind, MetaItemKind::Word)
}
pub fn has_name(&self, name: Symbol) -> bool {
}
crate fn may_have_suffix(self) -> bool {
- match self {
- Integer | Float | Err => true,
- _ => false,
- }
+ matches!(self, Integer | Float | Err)
}
}
}
pub fn should_end_const_arg(&self) -> bool {
- match self {
- Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true,
- _ => false,
- }
+ matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
}
}
}
pub fn is_op(&self) -> bool {
- match self.kind {
- OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
- | Lifetime(..) | Interpolated(..) | Eof => false,
- _ => true,
- }
+ !matches!(
+ self.kind,
+ OpenDelim(..)
+ | CloseDelim(..)
+ | Literal(..)
+ | DocComment(..)
+ | Ident(..)
+ | Lifetime(..)
+ | Interpolated(..)
+ | Eof
+ )
}
pub fn is_like_plus(&self) -> bool {
- match self.kind {
- BinOp(Plus) | BinOpEq(Plus) => true,
- _ => false,
- }
+ matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
}
/// Returns `true` if the token can appear at the start of an expression.
ModSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
- Interpolated(ref nt) => match **nt {
- NtLiteral(..) |
+ Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
NtExpr(..) |
NtBlock(..) |
- NtPath(..) => true,
- _ => false,
- },
+ NtPath(..)),
_ => false,
}
}
Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path
ModSep => true, // global path
- Interpolated(ref nt) => match **nt {
- NtTy(..) | NtPath(..) => true,
- _ => false,
- },
+ Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
_ => false,
}
}
pub fn can_begin_const_arg(&self) -> bool {
match self.kind {
OpenDelim(Brace) => true,
- Interpolated(ref nt) => match **nt {
- NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
- _ => false,
- },
+ Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
_ => self.can_begin_literal_maybe_minus(),
}
}
/// Returns `true` if the token is any literal.
pub fn is_lit(&self) -> bool {
- match self.kind {
- Literal(..) => true,
- _ => false,
- }
+ matches!(self.kind, Literal(..))
}
/// Returns `true` if the token is any literal, a minus (which can prefix a literal,
Delimited(DelimSpan, DelimToken, TokenStream),
}
+#[derive(Copy, Clone)]
+pub enum CanSynthesizeMissingTokens {
+ Yes,
+ No,
+}
+
// Ensure all fields of `TokenTree` is `Send` and `Sync`.
#[cfg(parallel_compiler)]
fn _dummy()
/// |x| 5
/// isn't parsed as (if true {...} else {...} | x) | 5
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
- match e.kind {
+ !matches!(
+ e.kind,
ast::ExprKind::If(..)
- | ast::ExprKind::Match(..)
- | ast::ExprKind::Block(..)
- | ast::ExprKind::While(..)
- | ast::ExprKind::Loop(..)
- | ast::ExprKind::ForLoop(..)
- | ast::ExprKind::TryBlock(..) => false,
- _ => true,
- }
+ | ast::ExprKind::Match(..)
+ | ast::ExprKind::Block(..)
+ | ast::ExprKind::While(..)
+ | ast::ExprKind::Loop(..)
+ | ast::ExprKind::ForLoop(..)
+ | ast::ExprKind::TryBlock(..)
+ )
}
/// Makes a doc string more presentable to users.
/// Used by rustdoc and perhaps other tools, but not by rustc.
-pub fn beautify_doc_string(data: Symbol) -> String {
- /// remove whitespace-only lines from the start/end of lines
- fn vertical_trim(lines: Vec<String>) -> Vec<String> {
+pub fn beautify_doc_string(data: Symbol) -> Symbol {
+ fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> {
let mut i = 0;
let mut j = lines.len();
// first line of all-stars should be omitted
j -= 1;
}
- lines[i..j].to_vec()
+ if i != 0 || j != lines.len() { Some((i, j)) } else { None }
}
- /// remove a "[ \t]*\*" block from each line, if possible
- fn horizontal_trim(lines: Vec<String>) -> Vec<String> {
+ fn get_horizontal_trim(lines: &[&str]) -> Option<usize> {
let mut i = usize::MAX;
- let mut can_trim = true;
let mut first = true;
- for line in &lines {
+ for line in lines {
for (j, c) in line.chars().enumerate() {
if j > i || !"* \t".contains(c) {
- can_trim = false;
- break;
+ return None;
}
if c == '*' {
if first {
i = j;
first = false;
} else if i != j {
- can_trim = false;
+ return None;
}
break;
}
}
if i >= line.len() {
- can_trim = false;
- }
- if !can_trim {
- break;
+ return None;
}
}
+ Some(i)
+ }
- if can_trim {
- lines.iter().map(|line| (&line[i + 1..line.len()]).to_string()).collect()
+ let data_s = data.as_str();
+ if data_s.contains('\n') {
+ let mut lines = data_s.lines().collect::<Vec<&str>>();
+ let mut changes = false;
+ let lines = if let Some((i, j)) = get_vertical_trim(&lines) {
+ changes = true;
+ // remove whitespace-only lines from the start/end of lines
+ &mut lines[i..j]
} else {
- lines
+ &mut lines
+ };
+ if let Some(horizontal) = get_horizontal_trim(&lines) {
+ changes = true;
+ // remove a "[ \t]*\*" block from each line, if possible
+ for line in lines.iter_mut() {
+ *line = &line[horizontal + 1..];
+ }
+ }
+ if changes {
+ return Symbol::intern(&lines.join("\n"));
}
}
-
- let data = data.as_str();
- if data.contains('\n') {
- let lines = data.lines().map(|s| s.to_string()).collect::<Vec<String>>();
- let lines = vertical_trim(lines);
- let lines = horizontal_trim(lines);
- lines.join("\n")
- } else {
- data.to_string()
- }
+ data
}
/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
}
rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
if doc_style.is_none() {
- let code_to_the_right = match text[pos + token.len..].chars().next() {
- Some('\r' | '\n') => false,
- _ => true,
- };
+ let code_to_the_right =
+ !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n'));
let style = match (code_to_the_left, code_to_the_right) {
(_, true) => CommentStyle::Mixed,
(false, false) => CommentStyle::Isolated,
with_default_session_globals(|| {
let comment = "\n * Test \n ** Test\n * Test\n";
let stripped = beautify_doc_string(Symbol::intern(comment));
- assert_eq!(stripped, " Test \n* Test\n Test");
+ assert_eq!(stripped.as_str(), " Test \n* Test\n Test");
})
}
with_default_session_globals(|| {
let comment = "\n * Test\n * Test\n";
let stripped = beautify_doc_string(Symbol::intern(comment));
- assert_eq!(stripped, " Test\n Test");
+ assert_eq!(stripped.as_str(), " Test\n Test");
})
}
with_default_session_globals(|| {
let comment = "\n let a: *i32;\n *a = 5;\n";
let stripped = beautify_doc_string(Symbol::intern(comment));
- assert_eq!(stripped, " let a: *i32;\n *a = 5;");
+ assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
})
}
fn test_line_doc_comment() {
with_default_session_globals(|| {
let stripped = beautify_doc_string(Symbol::intern(" test"));
- assert_eq!(stripped, " test");
+ assert_eq!(stripped.as_str(), " test");
let stripped = beautify_doc_string(Symbol::intern("! test"));
- assert_eq!(stripped, "! test");
+ assert_eq!(stripped.as_str(), "! test");
let stripped = beautify_doc_string(Symbol::intern("test"));
- assert_eq!(stripped, "test");
+ assert_eq!(stripped.as_str(), "test");
let stripped = beautify_doc_string(Symbol::intern("!test"));
- assert_eq!(stripped, "!test");
+ assert_eq!(stripped.as_str(), "!test");
})
}
use rustc_ast::node_id::NodeMap;
use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
-use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, DelimSpan, TokenStream, TokenTree};
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::walk_list;
use rustc_ast::{self as ast, *};
) -> LocalDefId;
}
-type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
+type NtToTokenstream =
+ fn(&Nonterminal, &ParseSess, Span, CanSynthesizeMissingTokens) -> TokenStream;
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has.
PassThrough,
}
+struct TokenStreamLowering<'a> {
+ parse_sess: &'a ParseSess,
+ synthesize_tokens: CanSynthesizeMissingTokens,
+ nt_to_tokenstream: NtToTokenstream,
+}
+
+impl<'a> TokenStreamLowering<'a> {
+ fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
+ tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect()
+ }
+
+ fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
+ match tree {
+ TokenTree::Token(token) => self.lower_token(token),
+ TokenTree::Delimited(span, delim, tts) => {
+ TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into()
+ }
+ }
+ }
+
+ fn lower_token(&mut self, token: Token) -> TokenStream {
+ match token.kind {
+ token::Interpolated(nt) => {
+ let tts = (self.nt_to_tokenstream)(
+ &nt,
+ self.parse_sess,
+ token.span,
+ self.synthesize_tokens,
+ );
+ TokenTree::Delimited(
+ DelimSpan::from_single(token.span),
+ DelimToken::NoDelim,
+ self.lower_token_stream(tts),
+ )
+ .into()
+ }
+ _ => TokenTree::Token(token).into(),
+ }
+ }
+}
+
struct ImplTraitTypeIdVisitor<'a> {
ids: &'a mut SmallVec<[NodeId; 1]>,
}
match *args {
MacArgs::Empty => MacArgs::Empty,
MacArgs::Delimited(dspan, delim, ref tokens) => {
- MacArgs::Delimited(dspan, delim, self.lower_token_stream(tokens.clone()))
- }
- MacArgs::Eq(eq_span, ref tokens) => {
- MacArgs::Eq(eq_span, self.lower_token_stream(tokens.clone()))
- }
- }
- }
-
- fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
- tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect()
- }
-
- fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
- match tree {
- TokenTree::Token(token) => self.lower_token(token),
- TokenTree::Delimited(span, delim, tts) => {
- TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into()
+ // This is either a non-key-value attribute, or a `macro_rules!` body.
+ // We either not have any nonterminals present (in the case of an attribute),
+ // or have tokens available for all nonterminals in the case of a nested
+ // `macro_rules`: e.g:
+ //
+ // ```rust
+ // macro_rules! outer {
+ // ($e:expr) => {
+ // macro_rules! inner {
+ // () => { $e }
+ // }
+ // }
+ // }
+ // ```
+ //
+ // In both cases, we don't want to synthesize any tokens
+ MacArgs::Delimited(
+ dspan,
+ delim,
+ self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No),
+ )
}
+ // This is an inert key-value attribute - it will never be visible to macros
+ // after it gets lowered to HIR. Therefore, we can synthesize tokens with fake
+ // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
+ MacArgs::Eq(eq_span, ref tokens) => MacArgs::Eq(
+ eq_span,
+ self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::Yes),
+ ),
}
}
- fn lower_token(&mut self, token: Token) -> TokenStream {
- match token.kind {
- token::Interpolated(nt) => {
- let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span);
- TokenTree::Delimited(
- DelimSpan::from_single(token.span),
- DelimToken::NoDelim,
- self.lower_token_stream(tts),
- )
- .into()
- }
- _ => TokenTree::Token(token).into(),
+ fn lower_token_stream(
+ &self,
+ tokens: TokenStream,
+ synthesize_tokens: CanSynthesizeMissingTokens,
+ ) -> TokenStream {
+ TokenStreamLowering {
+ parse_sess: &self.sess.parse_sess,
+ synthesize_tokens,
+ nt_to_tokenstream: self.nt_to_tokenstream,
}
+ .lower_token_stream(tokens)
}
/// Given an associated type constraint like one of these:
}
self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => ident,
- _ => Ident::new(kw::Invalid, param.pat.span),
+ _ => Ident::new(kw::Empty, param.pat.span),
}))
}
output,
c_variadic,
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
- let is_mutable_pat = match arg.pat.kind {
- PatKind::Ident(BindingMode::ByValue(mt) | BindingMode::ByRef(mt), _, _) => {
- mt == Mutability::Mut
- }
- _ => false,
- };
+ use BindingMode::{ByRef, ByValue};
+ let is_mutable_pat = matches!(
+ arg.pat.kind,
+ PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..)
+ );
match arg.ty.kind {
TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
}
fn check_lifetime(&self, ident: Ident) {
- let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
+ let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
}
err.span_suggestion(
span,
&format!(
- "reorder the parameters: lifetimes{}",
+ "reorder the parameters: lifetimes, {}",
if sess.features_untracked().const_generics {
- ", then consts and types"
- } else if sess.features_untracked().min_const_generics {
- ", then types, then consts"
+ "then consts and types"
} else {
- ", then types"
- },
+ "then types, then consts"
+ }
),
ordered_params.clone(),
Applicability::MachineApplicable,
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
-use rustc_ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
+use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
match i.kind {
ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
- let links_to_llvm = match link_name {
- Some(val) => val.as_str().starts_with("llvm."),
- _ => false,
- };
+ let links_to_llvm =
+ link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
if links_to_llvm {
gate_feature_post!(
&self,
visit::walk_fn(self, fn_kind, span)
}
- fn visit_generic_param(&mut self, param: &'a GenericParam) {
- if let GenericParamKind::Const { .. } = param.kind {
- gate_feature_fn!(
- &self,
- |x: &Features| x.const_generics || x.min_const_generics,
- param.ident.span,
- sym::min_const_generics,
- "const generics are unstable"
- );
- }
- visit::walk_generic_param(self, param)
- }
-
fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
gate_feature_post!(
//! breaking inconsistently to become
//!
//! ```
-//! foo(hello, there
+//! foo(hello, there,
//! good, friends);
//! ```
//!
//!
//! ```
//! foo(hello,
-//! there
+//! there,
//! good,
//! friends);
//! ```
self.print_explicit_self(&eself);
} else {
let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
- ident.name == kw::Invalid
+ ident.name == kw::Empty
} else {
false
};
| ItemKind::Enum(_, Generics { ref params, .. }) => {
let container_id = cx.current_expansion.id.expn_data().parent;
if cx.resolver.has_derive_copy(container_id)
- && !params.iter().any(|param| match param.kind {
- ast::GenericParamKind::Type { .. } => true,
- _ => false,
- })
+ && !params
+ .iter()
+ .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
{
bounds = vec![];
is_shallow = true;
pub type_ident: Ident,
/// ident of the method
pub method_ident: Ident,
- /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments
+ /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)][ptr]` arguments
+ ///
+ /// [`Self_`]: ty::Ty::Self_
+ /// [ptr]: ty::Ty::Ptr
pub self_args: &'a [P<Expr>],
/// verbatim access to any other arguments
pub nonself_args: &'a [P<Expr>],
let has_no_type_params = match item.kind {
ast::ItemKind::Struct(_, ref generics)
| ast::ItemKind::Enum(_, ref generics)
- | ast::ItemKind::Union(_, ref generics) => {
- !generics.params.iter().any(|param| match param.kind {
- ast::GenericParamKind::Type { .. } => true,
- _ => false,
- })
- }
+ | ast::ItemKind::Union(_, ref generics) => !generics
+ .params
+ .iter()
+ .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
_ => unreachable!(),
};
let container_id = cx.current_expansion.id.expn_data().parent;
Self_ if nonstatic => {
self_args.push(arg_expr);
}
- Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => {
+ Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
self_args.push(cx.expr_deref(trait_.span, arg_expr))
}
_ => {
let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
parse::String(_) => false,
- parse::NextArgument(arg) => match arg.position {
- parse::Position::ArgumentIs(_) => true,
- _ => false,
- },
+ parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)),
});
cx.build_index_map();
}
fn is_flag(c: &char) -> bool {
- match c {
- '0' | '-' | '+' | ' ' | '#' | '\'' => true,
- _ => false,
- }
+ matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'')
}
#[cfg(test)]
// parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
let first_colon = tts
.trees()
- .position(|tt| match tt {
- tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) => true,
- _ => false,
+ .position(|tt| {
+ matches!(
+ tt,
+ tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
+ )
})
.unwrap_or(tts.len());
let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
- let mut asm = kw::Invalid;
+ let mut asm = kw::Empty;
let mut asm_str_style = None;
let mut outputs = Vec::new();
let mut inputs = Vec::new();
// we're just not interested in this item.
//
// If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
- let is_fn = match item.kind {
- ast::ItemKind::Fn(..) => true,
- _ => false,
- };
+ let is_fn = matches!(item.kind, ast::ItemKind::Fn(..));
let mut found_attr: Option<&'a ast::Attribute> = None;
{
// source for rustc_* is not included in the rust-src component; disable the errors about this
"rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate"],
+ "rust-analyzer.assist.importMergeBehaviour": "last",
"rust-analyzer.cargo.loadOutDirsFromCheck": true,
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
[[package]]
name = "cranelift-bforest"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"byteorder",
"cranelift-bforest",
[[package]]
name = "cranelift-codegen-meta"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
[[package]]
name = "cranelift-codegen-shared"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
[[package]]
name = "cranelift-entity"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
[[package]]
name = "cranelift-frontend"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-codegen",
"log",
"target-lexicon",
]
+[[package]]
+name = "cranelift-jit"
+version = "0.68.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
+dependencies = [
+ "anyhow",
+ "cranelift-codegen",
+ "cranelift-entity",
+ "cranelift-module",
+ "cranelift-native",
+ "errno",
+ "libc",
+ "log",
+ "region",
+ "target-lexicon",
+ "winapi",
+]
+
[[package]]
name = "cranelift-module"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-native"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"cranelift-codegen",
"raw-cpuid",
[[package]]
name = "cranelift-object"
version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb"
dependencies = [
"anyhow",
"cranelift-codegen",
"target-lexicon",
]
-[[package]]
-name = "cranelift-simplejit"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
-dependencies = [
- "cranelift-codegen",
- "cranelift-entity",
- "cranelift-module",
- "cranelift-native",
- "errno",
- "libc",
- "log",
- "region",
- "target-lexicon",
- "winapi",
-]
-
[[package]]
name = "crc32fast"
version = "1.2.1"
"ar",
"cranelift-codegen",
"cranelift-frontend",
+ "cranelift-jit",
"cranelift-module",
"cranelift-object",
- "cranelift-simplejit",
"gimli",
"indexmap",
"libloading",
cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-simplejit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
target-lexicon = "0.11.0"
gimli = { version = "0.23.0", default-features = false, features = ["write"]}
#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
#cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
#cranelift-module = { path = "../wasmtime/cranelift/module" }
-#cranelift-simplejit = { path = "../wasmtime/cranelift/simplejit" }
+#cranelift-jit = { path = "../wasmtime/cranelift/jit" }
#cranelift-object = { path = "../wasmtime/cranelift/object" }
#[patch.crates-io]
[features]
default = ["jit", "inline_asm"]
-jit = ["cranelift-simplejit", "libloading"]
+jit = ["cranelift-jit", "libloading"]
inline_asm = []
[profile.dev]
> âš âš âš Certain kinds of FFI don't work yet. âš âš âš
-The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/master/cranelift).
+The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift).
This has the potential to improve compilation times in debug mode.
If your project doesn't use any of the things listed under "Not yet supported", it should work fine.
If not please open an issue.
or
```bash
-$ $cg_clif_dir/build/bin/cg_clif --jit my_crate.rs
+$ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+```
+
+There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
+first called. It currently does not work with multi-threaded programs. When a not yet compiled
+function is called from another thread than the main thread, you will get an ICE.
+
+```bash
+$ $cg_clif_dir/build/cargo.sh lazy-jit
```
### Shell
```bash
function jit_naked() {
- echo "$@" | $cg_clif_dir/build/bin/cg_clif - --jit
+ echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Cllvm-args=mode=jit -Cprefer-dynamic
}
function jit() {
[[package]]
name = "cc"
-version = "1.0.65"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
+checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
[[package]]
name = "libc"
-version = "0.2.80"
+version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
dependencies = [
"rustc-std-workspace-core",
]
[dependencies]
core = { path = "./sysroot_src/library/core" }
-compiler_builtins = "0.1"
alloc = { path = "./sysroot_src/library/alloc" }
std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
test = { path = "./sysroot_src/library/test" }
alloc_system = { path = "./alloc_system" }
+compiler_builtins = { version = "=0.1.36", default-features = false }
+
[patch.crates-io]
rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
let stderr = ::std::io::stderr();
let mut stderr = stderr.lock();
+ // FIXME support lazy jit when multi threading
+ #[cfg(not(lazy_jit))]
std::thread::spawn(move || {
println!("Hello from another thread!");
});
-nightly-2020-11-27
+nightly-2020-12-23
shift || true
if [[ "$cmd" = "jit" ]]; then
-cargo "+${TOOLCHAIN}" rustc "$@" -- --jit
+cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit -Cprefer-dynamic
+elif [[ "$cmd" = "lazy-jit" ]]; then
+cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit-lazy -Cprefer-dynamic
else
cargo "+${TOOLCHAIN}" "$cmd" "$@"
fi
pushd $(dirname "$0")/../
source build/config.sh
popd
-PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS --jit $0
+PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/
//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] mini_core_hello_world"
- CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC --jit example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
+ CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
+
+ echo "[JIT-lazy] mini_core_hello_world"
+ CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
else
echo "[JIT] mini_core_hello_world (skipped)"
fi
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] std_example"
- $MY_RUSTC --jit example/std_example.rs --target "$HOST_TRIPLE"
+ $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
+
+ echo "[JIT-lazy] std_example"
+ $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --cfg lazy_jit --target "$HOST_TRIPLE"
else
echo "[JIT] std_example (skipped)"
fi
}
pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
- let triple = crate::build_isa(sess, true).triple().clone();
+ let triple = crate::build_isa(sess).triple().clone();
let binary_format = match triple.binary_format {
target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
let mut builder = ObjectBuilder::new(
- crate::build_isa(sess, true),
+ crate::build_isa(sess),
name + ".o",
cranelift_module::default_libcall_names(),
)
context.eliminate_unreachable_code(cx.module.isa()).unwrap();
context.dce(cx.module.isa()).unwrap();
+ context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
+
// Define function
let module = &mut cx.module;
tcx.sess.time("define function", || {
&clif_comments,
);
+ if let Some(mach_compile_result) = &context.mach_compile_result {
+ if let Some(disasm) = &mach_compile_result.disasm {
+ crate::pretty_clif::write_ir_file(
+ tcx,
+ &format!("{}.vcode", tcx.symbol_name(instance).name),
+ |file| file.write_all(disasm.as_bytes()),
+ )
+ }
+ }
+
// Define debuginfo for function
let isa = cx.module.isa();
let debug_context = &mut cx.debug_context;
} => {
let discr = codegen_operand(fx, discr).load_scalar(fx);
- if switch_ty.kind() == fx.tcx.types.bool.kind() {
+ let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
+ || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
+ if use_bool_opt {
assert_eq!(targets.iter().count(), 1);
let (then_value, then_block) = targets.iter().next().unwrap();
let then_block = fx.get_block(then_block);
let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
let discr =
crate::optimize::peephole::make_branchable_value(&mut fx.bcx, discr);
- if test_zero {
- fx.bcx.ins().brz(discr, then_block, &[]);
- fx.bcx.ins().jump(else_block, &[]);
+ if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
+ &fx.bcx, discr, test_zero,
+ ) {
+ if taken {
+ fx.bcx.ins().jump(then_block, &[]);
+ } else {
+ fx.bcx.ins().jump(else_block, &[]);
+ }
} else {
- fx.bcx.ins().brnz(discr, then_block, &[]);
- fx.bcx.ins().jump(else_block, &[]);
+ if test_zero {
+ fx.bcx.ins().brz(discr, then_block, &[]);
+ fx.bcx.ins().jump(else_block, &[]);
+ } else {
+ fx.bcx.ins().brnz(discr, then_block, &[]);
+ fx.bcx.ins().jump(else_block, &[]);
+ }
}
} else {
let mut switch = ::cranelift_frontend::Switch::new();
let mut callbacks = CraneliftPassesCallbacks::default();
rustc_driver::install_ice_hook();
let exit_code = rustc_driver::catch_with_exit_code(|| {
- let mut use_jit = false;
-
- let mut args = std::env::args_os()
+ let args = std::env::args_os()
.enumerate()
.map(|(i, arg)| {
arg.into_string().unwrap_or_else(|arg| {
)
})
})
- .filter(|arg| {
- if arg == "--jit" {
- use_jit = true;
- false
- } else {
- true
- }
- })
.collect::<Vec<_>>();
- if use_jit {
- args.push("-Cprefer-dynamic".to_string());
- }
let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
- Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
- config: rustc_codegen_cranelift::BackendConfig { use_jit },
- })
+ Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
})));
run_compiler.run()
});
let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
if use_clif {
run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
- Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
- config: rustc_codegen_cranelift::BackendConfig { use_jit: false },
- })
+ Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
})));
}
run_compiler.run()
let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
assert!(!layout.is_unsized(), "unsized statics aren't supported");
assert!(
- matches!(fx.bcx.func.global_values[local_data_id], GlobalValueData::Symbol { tls: false, ..}),
+ matches!(
+ fx.bcx.func.global_values[local_data_id],
+ GlobalValueData::Symbol { tls: false, .. }
+ ),
"tls static referenced without Rvalue::ThreadLocalRef"
);
CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout)
data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
}
- module.define_data(data_id, &data_ctx).unwrap();
+ // FIXME don't duplicate definitions in lazy jit mode
+ let _ = module.define_data(data_id, &data_ctx);
cx.done.insert(data_id);
}
/// Perform the collected relocations to be usable for JIT usage.
#[cfg(feature = "jit")]
- pub(super) fn relocate_for_jit(
- mut self,
- jit_module: &cranelift_simplejit::SimpleJITModule,
- ) -> Vec<u8> {
+ pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
use std::convert::TryInto;
for reloc in self.relocs.drain(..) {
}
impl<'tcx> UnwindContext<'tcx> {
- pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
+ pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
let mut frame_table = FrameTable::default();
let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
- if isa.flags().is_pic() {
+ if pic_eh_frame {
cie.fde_address_encoding =
gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0);
}
#[cfg(feature = "jit")]
pub(crate) unsafe fn register_jit(
self,
- jit_module: &cranelift_simplejit::SimpleJITModule,
+ jit_module: &cranelift_jit::JITModule,
) -> Option<UnwindRegistry> {
let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(
self.tcx,
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
-use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{DebugInfo, OutputType};
}
}
- let mut cx = crate::CodegenCx::new(tcx, module, tcx.sess.opts.debuginfo != DebugInfo::None);
+ let mut cx = crate::CodegenCx::new(
+ tcx,
+ module,
+ tcx.sess.opts.debuginfo != DebugInfo::None,
+ true,
+ );
super::predefine_mono_items(&mut cx, &mono_items);
for (mono_item, (linkage, visibility)) in mono_items {
let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
- super::codegen_mono_item(&mut cx, mono_item, linkage);
+ match mono_item {
+ MonoItem::Fn(inst) => {
+ cx.tcx.sess.time("codegen fn", || {
+ crate::base::codegen_fn(&mut cx, inst, linkage)
+ });
+ }
+ MonoItem::Static(def_id) => {
+ crate::constant::codegen_static(&mut cx.constants_cx, def_id)
+ }
+ MonoItem::GlobalAsm(hir_id) => {
+ let item = cx.tcx.hir().expect_item(hir_id);
+ if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
+ cx.global_asm.push_str(&*asm.as_str());
+ cx.global_asm.push_str("\n\n");
+ } else {
+ bug!("Expected GlobalAsm found {:?}", item);
+ }
+ }
+ }
}
let (mut module, global_asm, debug, mut unwind_context) =
tcx.sess.time("finalize CodegenCx", || cx.finalize());
tcx.sess.abort_if_errors();
let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
- let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa());
+ let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
let created_alloc_shim =
crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
//! files.
+use std::cell::RefCell;
use std::ffi::CString;
use std::os::raw::{c_char, c_int};
use rustc_codegen_ssa::CrateInfo;
+use rustc_middle::mir::mono::MonoItem;
-use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule};
+use cranelift_jit::{JITBuilder, JITModule};
use crate::prelude::*;
+use crate::{CodegenCx, CodegenMode};
-pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
+thread_local! {
+ pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None);
+}
+
+pub(super) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode) -> ! {
if !tcx.sess.opts.output_types.should_codegen() {
tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
}
let imported_symbols = load_imported_symbols_for_jit(tcx);
- let mut jit_builder = SimpleJITBuilder::with_isa(
- crate::build_isa(tcx.sess, false),
+ let mut jit_builder = JITBuilder::with_isa(
+ crate::build_isa(tcx.sess),
cranelift_module::default_libcall_names(),
);
+ jit_builder.hotswap(matches!(codegen_mode, CodegenMode::JitLazy));
jit_builder.symbols(imported_symbols);
- let mut jit_module = SimpleJITModule::new(jit_builder);
+ let mut jit_module = JITModule::new(jit_builder);
assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
let sig = Signature {
.into_iter()
.collect::<Vec<(_, (_, _))>>();
- let mut cx = crate::CodegenCx::new(tcx, jit_module, false);
+ let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
- let (mut jit_module, global_asm, _debug, mut unwind_context) =
- super::time(tcx, "codegen mono items", || {
- super::predefine_mono_items(&mut cx, &mono_items);
- for (mono_item, (linkage, visibility)) in mono_items {
- let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
- super::codegen_mono_item(&mut cx, mono_item, linkage);
+ super::time(tcx, "codegen mono items", || {
+ super::predefine_mono_items(&mut cx, &mono_items);
+ for (mono_item, (linkage, visibility)) in mono_items {
+ let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
+ match mono_item {
+ MonoItem::Fn(inst) => match codegen_mode {
+ CodegenMode::Aot => unreachable!(),
+ CodegenMode::Jit => {
+ cx.tcx.sess.time("codegen fn", || {
+ crate::base::codegen_fn(&mut cx, inst, linkage)
+ });
+ }
+ CodegenMode::JitLazy => codegen_shim(&mut cx, inst),
+ },
+ MonoItem::Static(def_id) => {
+ crate::constant::codegen_static(&mut cx.constants_cx, def_id);
+ }
+ MonoItem::GlobalAsm(hir_id) => {
+ let item = cx.tcx.hir().expect_item(hir_id);
+ tcx.sess
+ .span_fatal(item.span, "Global asm is not supported in JIT mode");
+ }
}
- tcx.sess.time("finalize CodegenCx", || cx.finalize())
- });
+ }
+ });
+
+ let (mut jit_module, global_asm, _debug, mut unwind_context) =
+ tcx.sess.time("finalize CodegenCx", || cx.finalize());
+ jit_module.finalize_definitions();
+
if !global_asm.is_empty() {
- tcx.sess.fatal("Global asm is not supported in JIT mode");
+ tcx.sess.fatal("Inline asm is not supported in JIT mode");
}
+
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context, true);
crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
- println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed");
+ println!("Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed");
let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
unsafe { ::std::mem::transmute(finalized_main) };
// useful as some dynamic linkers use it as a marker to jump over.
argv.push(std::ptr::null());
+ CURRENT_MODULE
+ .with(|current_module| assert!(current_module.borrow_mut().replace(jit_module).is_none()));
+
let ret = f(args.len() as c_int, argv.as_ptr());
std::process::exit(ret);
}
+#[no_mangle]
+extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 {
+ rustc_middle::ty::tls::with(|tcx| {
+ // lift is used to ensure the correct lifetime for instance.
+ let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
+
+ CURRENT_MODULE.with(|jit_module| {
+ let mut jit_module = jit_module.borrow_mut();
+ let jit_module = jit_module.as_mut().unwrap();
+ let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
+
+ let (name, sig) = crate::abi::get_function_name_and_sig(
+ tcx,
+ cx.module.isa().triple(),
+ instance,
+ true,
+ );
+ let func_id = cx
+ .module
+ .declare_function(&name, Linkage::Export, &sig)
+ .unwrap();
+ cx.module.prepare_for_function_redefine(func_id).unwrap();
+
+ tcx.sess.time("codegen fn", || {
+ crate::base::codegen_fn(&mut cx, instance, Linkage::Export)
+ });
+
+ let (jit_module, global_asm, _debug_context, unwind_context) = cx.finalize();
+ assert!(global_asm.is_empty());
+ jit_module.finalize_definitions();
+ std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) });
+ jit_module.get_finalized_function(func_id)
+ })
+ })
+}
+
fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
use rustc_middle::middle::dependency_format::Linkage;
imported_symbols
}
+
+pub(super) fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx, impl Module>, inst: Instance<'tcx>) {
+ let tcx = cx.tcx;
+
+ let pointer_type = cx.module.target_config().pointer_type();
+
+ let (name, sig) =
+ crate::abi::get_function_name_and_sig(tcx, cx.module.isa().triple(), inst, true);
+ let func_id = cx
+ .module
+ .declare_function(&name, Linkage::Export, &sig)
+ .unwrap();
+
+ let instance_ptr = Box::into_raw(Box::new(inst));
+
+ let jit_fn = cx
+ .module
+ .declare_function(
+ "__clif_jit_fn",
+ Linkage::Import,
+ &Signature {
+ call_conv: cx.module.target_config().default_call_conv,
+ params: vec![AbiParam::new(pointer_type)],
+ returns: vec![AbiParam::new(pointer_type)],
+ },
+ )
+ .unwrap();
+
+ let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone());
+ let mut builder_ctx = FunctionBuilderContext::new();
+ let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx);
+
+ let jit_fn = cx
+ .module
+ .declare_func_in_func(jit_fn, trampoline_builder.func);
+ let sig_ref = trampoline_builder.func.import_signature(sig);
+
+ let entry_block = trampoline_builder.create_block();
+ trampoline_builder.append_block_params_for_function_params(entry_block);
+ let fn_args = trampoline_builder
+ .func
+ .dfg
+ .block_params(entry_block)
+ .to_vec();
+
+ trampoline_builder.switch_to_block(entry_block);
+ let instance_ptr = trampoline_builder
+ .ins()
+ .iconst(pointer_type, instance_ptr as u64 as i64);
+ let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr]);
+ let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0];
+ let call_inst = trampoline_builder
+ .ins()
+ .call_indirect(sig_ref, jitted_fn, &fn_args);
+ let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
+ trampoline_builder.ins().return_(&ret_vals);
+
+ cx.module
+ .define_function(
+ func_id,
+ &mut Context::for_function(trampoline),
+ &mut cranelift_codegen::binemit::NullTrapSink {},
+ )
+ .unwrap();
+}
use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
use crate::prelude::*;
+use crate::CodegenMode;
mod aot;
#[cfg(feature = "jit")]
) -> Box<dyn Any> {
tcx.sess.abort_if_errors();
- if config.use_jit {
- let is_executable = tcx
- .sess
- .crate_types()
- .contains(&rustc_session::config::CrateType::Executable);
- if !is_executable {
- tcx.sess.fatal("can't jit non-executable crate");
- }
+ match config.codegen_mode {
+ CodegenMode::Aot => aot::run_aot(tcx, metadata, need_metadata_module),
+ CodegenMode::Jit | CodegenMode::JitLazy => {
+ let is_executable = tcx
+ .sess
+ .crate_types()
+ .contains(&rustc_session::config::CrateType::Executable);
+ if !is_executable {
+ tcx.sess.fatal("can't jit non-executable crate");
+ }
- #[cfg(feature = "jit")]
- let _: ! = jit::run_jit(tcx);
+ #[cfg(feature = "jit")]
+ let _: ! = jit::run_jit(tcx, config.codegen_mode);
- #[cfg(not(feature = "jit"))]
- tcx.sess
- .fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+ #[cfg(not(feature = "jit"))]
+ tcx.sess
+ .fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+ }
}
-
- aot::run_aot(tcx, metadata, need_metadata_module)
}
fn predefine_mono_items<'tcx>(
});
}
-fn codegen_mono_item<'tcx, M: Module>(
- cx: &mut crate::CodegenCx<'tcx, M>,
- mono_item: MonoItem<'tcx>,
- linkage: Linkage,
-) {
- match mono_item {
- MonoItem::Fn(inst) => {
- cx.tcx
- .sess
- .time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage));
- }
- MonoItem::Static(def_id) => crate::constant::codegen_static(&mut cx.constants_cx, def_id),
- MonoItem::GlobalAsm(hir_id) => {
- let item = cx.tcx.hir().expect_item(hir_id);
- if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
- cx.global_asm.push_str(&*asm.as_str());
- cx.global_asm.push_str("\n\n");
- } else {
- bug!("Expected GlobalAsm found {:?}", item);
- }
- }
- }
-}
-
fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
if std::env::var("CG_CLIF_DISPLAY_CG_TIME")
.as_ref()
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) {
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, a.layout());
- let lane_ty = fx.clif_type(lane_layout.ty).unwrap();
+ let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_ty = fx.clif_type(lane_ty).unwrap();
assert!(lane_count <= 32);
let mut res = fx.bcx.ins().iconst(types::I32, 0);
}
}
-fn lane_type_and_count<'tcx>(
- tcx: TyCtxt<'tcx>,
- layout: TyAndLayout<'tcx>,
-) -> (TyAndLayout<'tcx>, u16) {
- assert!(layout.ty.is_simd());
- let lane_count = match layout.fields {
- rustc_target::abi::FieldsShape::Array { stride: _, count } => u16::try_from(count).unwrap(),
- _ => unreachable!("lane_type_and_count({:?})", layout),
- };
- let lane_layout = layout
- .field(
- &ty::layout::LayoutCx {
- tcx,
- param_env: ParamEnv::reveal_all(),
- },
- 0,
- )
- .unwrap();
- (lane_layout, lane_count)
-}
-
pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
let (element, count) = match &layout.abi {
Abi::Vector { element, count } => (element.clone(), *count),
) {
let layout = val.layout();
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+ let ret_lane_layout = fx.layout_of(ret_lane_ty);
assert_eq!(lane_count, ret_lane_count);
for lane_idx in 0..lane_count {
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+ let ret_lane_layout = fx.layout_of(ret_lane_ty);
assert_eq!(lane_count, ret_lane_count);
for lane in 0..lane_count {
ret: CPlace<'tcx>,
f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, TyAndLayout<'tcx>, Value, Value) -> Value,
) {
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
+ let (lane_count, lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
assert_eq!(lane_layout, ret.layout());
let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
for lane_idx in 1..lane_count {
let lane = val
- .value_field(fx, mir::Field::new(lane_idx.into()))
+ .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
.load_scalar(fx);
res_val = f(fx, lane_layout, res_val, lane);
}
ret: CPlace<'tcx>,
f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, Value, Value) -> Value,
) {
- let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
+ let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
assert!(ret.layout().ty.is_bool());
let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean
for lane_idx in 1..lane_count {
let lane = val
- .value_field(fx, mir::Field::new(lane_idx.into()))
+ .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
.load_scalar(fx);
let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
res_val = f(fx, res_val, lane);
"abort" => {
trap_abort(fx, "Called intrinsic::abort.");
}
- "unreachable" => {
- trap_unreachable(fx, "[corruption] Called intrinsic::unreachable.");
- }
"transmute" => {
crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
}
fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
}
};
- discriminant_value, (c ptr) {
- let pointee_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
- let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), pointee_layout);
- let discr = crate::discriminant::codegen_get_discriminant(fx, val, ret.layout());
- ret.write_cvalue(fx, discr);
- };
size_of_val, <T> (c ptr) {
let layout = fx.layout_of(T);
let size = if layout.is_unsized() {
);
ret.write_cvalue(fx, res);
};
- _ if intrinsic.starts_with("wrapping_"), (c x, c y) {
- assert_eq!(x.layout().ty, y.layout().ty);
- let bin_op = match intrinsic {
- "wrapping_add" => BinOp::Add,
- "wrapping_sub" => BinOp::Sub,
- "wrapping_mul" => BinOp::Mul,
- _ => unreachable!("intrinsic {}", intrinsic),
- };
- let res = crate::num::codegen_int_binop(
- fx,
- bin_op,
- x,
- y,
- );
- ret.write_cvalue(fx, res);
- };
_ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) {
assert_eq!(lhs.layout().ty, rhs.layout().ty);
let bin_op = match intrinsic {
dest.write_cvalue(fx, val);
};
- size_of | pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
+ pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
let const_val =
fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
let val = crate::constant::codegen_const_value(
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
- let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
- assert_eq!(lane_type, ret_lane_type);
- assert_eq!(n, ret_lane_count);
+ assert_eq!(lane_ty, ret_lane_ty);
+ assert_eq!(u64::from(n), ret_lane_count);
let total_len = lane_count * 2;
};
for &idx in &indexes {
- assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
+ assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
}
for (out_idx, in_idx) in indexes.into_iter().enumerate() {
- let in_lane = if in_idx < lane_count {
+ let in_lane = if u64::from(in_idx) < lane_count {
x.value_field(fx, mir::Field::new(in_idx.into()))
} else {
- y.value_field(fx, mir::Field::new((in_idx - lane_count).into()))
+ y.value_field(fx, mir::Field::new(usize::from(in_idx) - usize::try_from(lane_count).unwrap()))
};
let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
out_lane.write_cvalue(fx, in_lane);
};
let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
- let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout());
+ let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
}
};
let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
- let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout());
+ let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
}
assert_eq!(a.layout(), c.layout());
let layout = a.layout();
- let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(lane_count, ret_lane_count);
+ let ret_lane_layout = fx.layout_of(ret_lane_ty);
for lane in 0..lane_count {
- let lane = mir::Field::new(lane.into());
+ let lane = mir::Field::new(lane.try_into().unwrap());
let a_lane = a.value_field(fx, lane).load_scalar(fx);
let b_lane = b.value_field(fx, lane).load_scalar(fx);
let c_lane = c.value_field(fx, lane).load_scalar(fx);
associated_type_bounds,
never_type,
try_blocks,
- hash_drain_filter
+ hash_drain_filter,
+ str_split_once
)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
extern crate rustc_driver;
use std::any::Any;
+use std::str::FromStr;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
}
impl<'tcx, M: Module> CodegenCx<'tcx, M> {
- fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool) -> Self {
- let unwind_context = UnwindContext::new(tcx, module.isa());
+ fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool, pic_eh_frame: bool) -> Self {
+ let unwind_context = UnwindContext::new(tcx, module.isa(), pic_eh_frame);
let debug_context = if debug_info {
Some(DebugContext::new(tcx, module.isa()))
} else {
}
#[derive(Copy, Clone, Debug)]
+pub enum CodegenMode {
+ Aot,
+ Jit,
+ JitLazy,
+}
+
+impl Default for CodegenMode {
+ fn default() -> Self {
+ CodegenMode::Aot
+ }
+}
+
+impl FromStr for CodegenMode {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "aot" => Ok(CodegenMode::Aot),
+ "jit" => Ok(CodegenMode::Jit),
+ "jit-lazy" => Ok(CodegenMode::JitLazy),
+ _ => Err(format!("Unknown codegen mode `{}`", s)),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
pub struct BackendConfig {
- pub use_jit: bool,
+ pub codegen_mode: CodegenMode,
+}
+
+impl BackendConfig {
+ fn from_opts(opts: &[String]) -> Result<Self, String> {
+ let mut config = BackendConfig::default();
+ for opt in opts {
+ if let Some((name, value)) = opt.split_once('=') {
+ match name {
+ "mode" => config.codegen_mode = value.parse()?,
+ _ => return Err(format!("Unknown option `{}`", name)),
+ }
+ } else {
+ return Err(format!("Invalid option `{}`", opt));
+ }
+ }
+ Ok(config)
+ }
}
pub struct CraneliftCodegenBackend {
- pub config: BackendConfig,
+ pub config: Option<BackendConfig>,
}
impl CodegenBackend for CraneliftCodegenBackend {
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<dyn Any> {
- let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);
+ let config = if let Some(config) = self.config {
+ config
+ } else {
+ BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
+ .unwrap_or_else(|err| tcx.sess.fatal(&err))
+ };
+ let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config);
rustc_symbol_mangling::test::report_symbol_names(tcx);
sess.target.llvm_target.parse().unwrap()
}
-fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
+fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
use target_lexicon::BinaryFormat;
let target_triple = crate::target_triple(sess);
let mut flags_builder = settings::builder();
- if enable_pic {
- flags_builder.enable("is_pic").unwrap();
- } else {
- flags_builder.set("is_pic", "false").unwrap();
- }
+ flags_builder.enable("is_pic").unwrap();
flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
flags_builder
.set(
flags_builder.set("enable_simd", "true").unwrap();
- // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
- /*
use rustc_session::config::OptLevel;
match sess.opts.optimize {
OptLevel::No => {
OptLevel::Size | OptLevel::SizeMin => {
sess.warn("Optimizing for size is not supported. Just ignoring the request");
}
- }*/
+ }
let flags = settings::Flags::new(flags_builder);
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
- Box::new(CraneliftCodegenBackend {
- config: BackendConfig { use_jit: false },
- })
+ Box::new(CraneliftCodegenBackend { config: None })
}
})()
.unwrap_or_else(|| {
match bcx.func.dfg.value_type(arg) {
- types::I8 | types::I32 => {
+ types::I8 | types::I16 => {
// WORKAROUND for brz.i8 and brnz.i8 not yet being implemented
bcx.ins().uextend(types::I32, arg)
}
}
})
}
+
+/// Returns whether the branch is statically known to be taken or `None` if it isn't statically known.
+pub(crate) fn maybe_known_branch_taken(
+ bcx: &FunctionBuilder<'_>,
+ arg: Value,
+ test_zero: bool,
+) -> Option<bool> {
+ let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
+ arg_inst
+ } else {
+ return None;
+ };
+
+ match bcx.func.dfg[arg_inst] {
+ InstructionData::UnaryBool {
+ opcode: Opcode::Bconst,
+ imm,
+ } => {
+ if test_zero {
+ Some(!imm)
+ } else {
+ Some(imm)
+ }
+ }
+ InstructionData::UnaryImm {
+ opcode: Opcode::Iconst,
+ imm,
+ } => {
+ if test_zero {
+ Some(imm.bits() == 0)
+ } else {
+ Some(imm.bits() != 0)
+ }
+ }
+ _ => None,
+ }
+}
//! ```
use std::fmt;
+use std::io::Write;
use cranelift_codegen::{
entity::SecondaryMap,
}
}
-pub(crate) fn write_clif_file<'tcx>(
- tcx: TyCtxt<'tcx>,
- postfix: &str,
- isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
- instance: Instance<'tcx>,
- context: &cranelift_codegen::Context,
- mut clif_comments: &CommentWriter,
-) {
- use std::io::Write;
-
- if !cfg!(debug_assertions)
- && !tcx
+pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
+ cfg!(debug_assertions)
+ || tcx
.sess
.opts
.output_types
.contains_key(&OutputType::LlvmAssembly)
- {
+}
+
+pub(crate) fn write_ir_file<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ name: &str,
+ write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
+) {
+ if !should_write_ir(tcx) {
return;
}
- let value_ranges = isa.map(|isa| {
- context
- .build_value_labels_ranges(isa)
- .expect("value location ranges")
- });
-
let clif_output_dir = tcx.output_filenames(LOCAL_CRATE).with_extension("clif");
match std::fs::create_dir(&clif_output_dir) {
res @ Err(_) => res.unwrap(),
}
- let clif_file_name = clif_output_dir.join(format!(
- "{}.{}.clif",
- tcx.symbol_name(instance).name,
- postfix
- ));
-
- let mut clif = String::new();
- cranelift_codegen::write::decorate_function(
- &mut clif_comments,
- &mut clif,
- &context.func,
- &DisplayFunctionAnnotations {
- isa: Some(&*crate::build_isa(
- tcx.sess, true, /* PIC doesn't matter here */
- )),
- value_ranges: value_ranges.as_ref(),
- },
- )
- .unwrap();
+ let clif_file_name = clif_output_dir.join(name);
let res: std::io::Result<()> = try {
let mut file = std::fs::File::create(clif_file_name)?;
- let target_triple = crate::target_triple(tcx.sess);
- writeln!(file, "test compile")?;
- writeln!(file, "set is_pic")?;
- writeln!(file, "set enable_simd")?;
- writeln!(file, "target {} haswell", target_triple)?;
- writeln!(file)?;
- file.write_all(clif.as_bytes())?;
+ write(&mut file)?;
};
if let Err(err) = res {
- tcx.sess.warn(&format!("err writing clif file: {}", err));
+ tcx.sess.warn(&format!("error writing ir file: {}", err));
}
}
+pub(crate) fn write_clif_file<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ postfix: &str,
+ isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
+ instance: Instance<'tcx>,
+ context: &cranelift_codegen::Context,
+ mut clif_comments: &CommentWriter,
+) {
+ write_ir_file(
+ tcx,
+ &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
+ |file| {
+ let value_ranges = isa.map(|isa| {
+ context
+ .build_value_labels_ranges(isa)
+ .expect("value location ranges")
+ });
+
+ let mut clif = String::new();
+ cranelift_codegen::write::decorate_function(
+ &mut clif_comments,
+ &mut clif,
+ &context.func,
+ &DisplayFunctionAnnotations {
+ isa: Some(&*crate::build_isa(tcx.sess)),
+ value_ranges: value_ranges.as_ref(),
+ },
+ )
+ .unwrap();
+
+ writeln!(file, "test compile")?;
+ writeln!(file, "set is_pic")?;
+ writeln!(file, "set enable_simd")?;
+ writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
+ writeln!(file)?;
+ file.write_all(clif.as_bytes())?;
+ Ok(())
+ },
+ );
+}
+
impl<M: Module> fmt::Debug for FunctionCx<'_, '_, M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{:?}", self.instance.substs)?;
)
.unwrap();
- fx.cx.module.define_data(data_id, &data_ctx).unwrap();
+ // FIXME don't duplicate definitions in lazy jit mode
+ let _ = fx.cx.module.define_data(data_id, &data_ctx);
data_id
}
diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig,
-) -> Result<(), FatalError> {
+) {
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]);
let llmod = module.module_llvm.llmod();
_ => llvm::OptStage::PreLinkNoLTO,
};
optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
- return Ok(());
+ return;
}
if cgcx.prof.llvm_recording_enabled() {
llvm::LLVMDisposePassManager(fpm);
llvm::LLVMDisposePassManager(mpm);
}
- Ok(())
}
unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
DIB(cx),
composite_type_metadata,
Some(type_array),
- type_params,
+ Some(type_params),
);
}
}
/// Computes the type parameters for a type, if any, for the given metadata.
-fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> {
+fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIArray {
if let ty::Adt(def, substs) = *ty.kind() {
if substs.types().next().is_some() {
let generics = cx.tcx.generics_of(def.did);
})
.collect();
- return Some(create_DIArray(DIB(cx), &template_params[..]));
+ return create_DIArray(DIB(cx), &template_params[..]);
}
}
- return Some(create_DIArray(DIB(cx), &[]));
+ return create_DIArray(DIB(cx), &[]);
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
let mut names = generics
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
) -> Result<(), FatalError> {
- back::write::optimize(cgcx, diag_handler, module, config)
+ Ok(back::write::optimize(cgcx, diag_handler, module, config))
}
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
codegen_results: CodegenResults,
outputs: &OutputFilenames,
) -> Result<(), ErrorReported> {
+ use crate::back::archive::LlvmArchiveBuilder;
+ use rustc_codegen_ssa::back::link::link_binary;
+
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
- sess.time("link_crate", || {
- use crate::back::archive::LlvmArchiveBuilder;
- use rustc_codegen_ssa::back::link::link_binary;
-
- let target_cpu = crate::llvm_util::target_cpu(sess);
- link_binary::<LlvmArchiveBuilder<'_>>(
- sess,
- &codegen_results,
- outputs,
- &codegen_results.crate_name.as_str(),
- target_cpu,
- );
- });
+ let target_cpu = crate::llvm_util::target_cpu(sess);
+ link_binary::<LlvmArchiveBuilder<'_>>(
+ sess,
+ &codegen_results,
+ outputs,
+ &codegen_results.crate_name.as_str(),
+ target_cpu,
+ );
Ok(())
}
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
+use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet};
use super::linker::{self, Linker};
use super::rpath::{self, RPathConfig};
use crate::{
- looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME,
+ looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+ METADATA_FILENAME,
};
use cc::windows_registry;
use rustc_session::config::{self, EntryFnType};
use rustc_session::utils::NativeLibKind;
use rustc_session::Session;
-use rustc_symbol_mangling::test as symbol_names_test;
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
use std::cmp;
ongoing_codegen.codegen_finished(tcx);
- finalize_tcx(tcx);
-
ongoing_codegen.check_for_errors(tcx.sess);
return ongoing_codegen;
total_codegen_time.into_inner(),
);
- rustc_incremental::assert_module_sources::assert_module_sources(tcx);
-
- symbol_names_test::report_symbol_names(tcx);
-
ongoing_codegen.check_for_errors(tcx.sess);
- finalize_tcx(tcx);
-
ongoing_codegen.into_inner()
}
}
}
-fn finalize_tcx(tcx: TyCtxt<'_>) {
- tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
- tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
-
- // We assume that no queries are run past here. If there are new queries
- // after this point, they'll show up as "<unknown>" in self-profiling data.
- {
- let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
- tcx.alloc_self_profile_query_strings();
- }
-}
-
impl CrateInfo {
pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
let mut info = CrateInfo {
profiler_runtime: None,
is_no_builtins: Default::default(),
native_libraries: Default::default(),
- used_libraries: tcx.native_libraries(LOCAL_CRATE),
+ used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
link_args: tcx.link_args(LOCAL_CRATE),
crate_name: Default::default(),
used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic),
info.missing_lang_items.reserve(n_crates);
for &cnum in crates.iter() {
- info.native_libraries.insert(cnum, tcx.native_libraries(cnum));
+ info.native_libraries
+ .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
if tcx.is_panic_runtime(cnum) {
#[macro_use]
extern crate rustc_middle;
+use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_hir::def_id::CrateNum;
use rustc_hir::LangItem;
use rustc_middle::dep_graph::WorkProduct;
-use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib};
+use rustc_middle::middle::cstore::{self, CrateSource, LibSource};
use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::ty::query::Providers;
use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT};
+use rustc_session::utils::NativeLibKind;
use rustc_span::symbol::Symbol;
use std::path::{Path, PathBuf};
}
}
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
+pub struct NativeLib {
+ pub kind: NativeLibKind,
+ pub name: Option<Symbol>,
+ pub cfg: Option<ast::MetaItem>,
+}
+
+impl From<&cstore::NativeLib> for NativeLib {
+ fn from(lib: &cstore::NativeLib) -> Self {
+ NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() }
+ }
+}
+
/// Misc info we load from metadata to persist beyond the tcx.
///
/// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo`
pub compiler_builtins: Option<CrateNum>,
pub profiler_runtime: Option<CrateNum>,
pub is_no_builtins: FxHashSet<CrateNum>,
- pub native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLib>>>,
+ pub native_libraries: FxHashMap<CrateNum, Vec<NativeLib>>,
pub crate_name: FxHashMap<CrateNum, String>,
- pub used_libraries: Lrc<Vec<NativeLib>>,
+ pub used_libraries: Vec<NativeLib>,
pub link_args: Lrc<Vec<String>>,
pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
pub used_crates_static: Vec<(CrateNum, LibSource)>,
};
// Allow uses of projections that are ZSTs or from scalar fields.
- let is_consume = match context {
+ let is_consume = matches!(
+ context,
PlaceContext::NonMutatingUse(
NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
- ) => true,
- _ => false,
- };
+ )
+ );
if is_consume {
let base_ty =
mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx());
mut bx: Bx,
terminator: &mir::Terminator<'tcx>,
func: &mir::Operand<'tcx>,
- args: &Vec<mir::Operand<'tcx>>,
+ args: &[mir::Operand<'tcx>],
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>,
fn_span: Span,
// (after #67586 gets fixed).
None
} else {
- let name = kw::Invalid;
+ let name = kw::Empty;
let decl = &self.mir.local_decls[local];
let dbg_var = if full_debug_info {
self.adjusted_span_and_dbg_scope(decl.source_info).map(
None
} else {
Some(match whole_local_var.or(fallback_var) {
- Some(var) if var.name != kw::Invalid => var.name.to_string(),
+ Some(var) if var.name != kw::Empty => var.name.to_string(),
_ => format!("{:?}", local),
})
};
successors_len: 0,
min_depth: depth,
min_cycle_root: successor_node,
- successor_node: successor_node,
+ successor_node,
});
continue 'recurse;
}
#![feature(fn_traits)]
#![feature(int_bits_const)]
#![feature(min_specialization)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
#![feature(thread_id_value)]
#![feature(extend_one)]
#![feature(const_panic)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
#![feature(new_uninit)]
#![feature(once_cell)]
#![feature(maybe_uninit_uninit_array)]
}
}
-fn show_content_with_pager(content: &String) {
+fn show_content_with_pager(content: &str) {
let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
});
Erroneous code example:
```compile_fail,E0730
-#![feature(const_generics)]
-
fn is_123<const N: usize>(x: [u32; N]) -> bool {
match x {
[1, 2, ..] => true, // error: cannot pattern-match on an
To fix this error, use a concrete type for the const parameter:
```
-#![feature(const_generics)]
fn foo<T, const N: usize>() {}
```
use crate::module::DirectoryOwnership;
use rustc_ast::ptr::P;
-use rustc_ast::token;
-use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, Attribute, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
}
}
- crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
- let nt = match self {
+ crate fn into_nonterminal(self) -> Nonterminal {
+ match self {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => {
token::NtItem(P(item.and_then(ast::AssocItem::into_item)))
| Annotatable::Param(..)
| Annotatable::StructField(..)
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
- };
- nt_to_tokenstream(&nt, sess, DUMMY_SP)
+ }
+ }
+
+ crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
+ nt_to_tokenstream(&self.into_nonterminal(), sess, DUMMY_SP, CanSynthesizeMissingTokens::No)
}
pub fn expect_item(self) -> P<ast::Item> {
pub struct StripUnconfigured<'a> {
pub sess: &'a Session,
pub features: Option<&'a Features>,
+ pub modified: bool,
}
fn get_features(
// `cfg_attr`-process the crate's attributes and compute the crate's features.
pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) {
- let mut strip_unconfigured = StripUnconfigured { sess, features: None };
+ let mut strip_unconfigured = StripUnconfigured { sess, features: None, modified: false };
let unconfigured_attrs = krate.attrs.clone();
let diag = &sess.parse_sess.span_diagnostic;
impl<'a> StripUnconfigured<'a> {
pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
- self.in_cfg(node.attrs()).then_some(node)
+ if self.in_cfg(node.attrs()) {
+ Some(node)
+ } else {
+ self.modified = true;
+ None
+ }
}
/// Parse and expand all `cfg_attr` attributes into a list of attributes
return vec![attr];
}
+ // A `#[cfg_attr]` either gets removed, or replaced with a new attribute
+ self.modified = true;
+
let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
None => return vec![],
Some(r) => r,
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path};
+use rustc_ast::{self as ast, AttrItem, AttrStyle, Block, LitKind, NodeId, PatKind, Path};
use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
(item, Vec::new())
} else {
- let mut item = StripUnconfigured {
+ let mut visitor = StripUnconfigured {
sess: self.cx.sess,
features: self.cx.ecfg.features,
- }
- .fully_configure(item);
+ modified: false,
+ };
+ let mut item = visitor.fully_configure(item);
item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+ if visitor.modified && !derives.is_empty() {
+ // Erase the tokens if cfg-stripping modified the item
+ // This will cause us to synthesize fake tokens
+ // when `nt_to_tokenstream` is called on this item.
+ match &mut item {
+ Annotatable::Item(item) => item.tokens = None,
+ Annotatable::Stmt(stmt) => {
+ if let StmtKind::Item(item) = &mut stmt.kind {
+ item.tokens = None
+ } else {
+ panic!("Unexpected stmt {:?}", stmt);
+ }
+ }
+ _ => panic!("Unexpected annotatable {:?}", item),
+ }
+ }
invocations.reserve(derives.len());
let derive_placeholders = derives
let invocations = {
let mut collector = InvocationCollector {
- cfg: StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features },
+ cfg: StripUnconfigured {
+ sess: &self.cx.sess,
+ features: self.cx.ecfg.features,
+ modified: false,
+ },
cx: self.cx,
invocations: Vec::new(),
monotonic: self.monotonic,
SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item);
- let tokens = item.into_tokens(&self.cx.sess.parse_sess);
+ let tokens = match attr.style {
+ AttrStyle::Outer => item.into_tokens(&self.cx.sess.parse_sess),
+ // FIXME: Properly collect tokens for inner attributes
+ AttrStyle::Inner => rustc_parse::fake_token_stream(
+ &self.cx.sess.parse_sess,
+ &item.into_nonterminal(),
+ span,
+ ),
+ };
let attr_item = attr.unwrap_normal_item();
if let MacArgs::Eq(..) = attr_item.args {
self.cx.span_err(span, "key-value macro attributes are not supported");
/// e.g., `$var`
MetaVar(Span, Ident),
/// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
- MetaVarDecl(Span, Ident /* name to bind */, NonterminalKind),
+ MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
}
impl TokenTree {
n_rec(sess, next_m, res.by_ref(), ret_val)?;
}
}
+ TokenTree::MetaVarDecl(span, _, None) => {
+ if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
+ return Err((span, "missing fragment specifier".to_string()));
+ }
+ }
TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val
.entry(MacroRulesNormalizedIdent::new(bind_name))
{
///
/// A `ParseResult`. Note that matches are kept track of through the items generated.
fn inner_parse_loop<'root, 'tt>(
+ sess: &ParseSess,
cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
})));
}
+ // We need to match a metavar (but the identifier is invalid)... this is an error
+ TokenTree::MetaVarDecl(span, _, None) => {
+ if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
+ return Error(span, "missing fragment specifier".to_string());
+ }
+ }
+
// We need to match a metavar with a valid ident... call out to the black-box
// parser by adding an item to `bb_items`.
- TokenTree::MetaVarDecl(span, _, kind) => {
+ TokenTree::MetaVarDecl(span, _, Some(kind)) => {
// Built-in nonterminals never start with these tokens, so we can eliminate
// them from consideration.
//
// parsing from the black-box parser done. The result is that `next_items` will contain a
// bunch of possible next matcher positions in `next_items`.
match inner_parse_loop(
+ parser.sess,
&mut cur_items,
&mut next_items,
&mut eof_items,
let nts = bb_items
.iter()
.map(|item| match item.top_elts.get_tt(item.idx) {
- TokenTree::MetaVarDecl(_, bind, kind) => format!("{} ('{}')", kind, bind),
+ TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
_ => panic!(),
})
.collect::<Vec<String>>()
assert_eq!(bb_items.len(), 1);
let mut item = bb_items.pop().unwrap();
- if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) {
+ if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) {
let match_cur = item.match_cur;
// We use the span of the metavariable declaration to determine any
// edition-specific matching behavior for non-terminals.
let diag = &sess.parse_sess.span_diagnostic;
let lhs_nm = Ident::new(sym::lhs, def.span);
let rhs_nm = Ident::new(sym::rhs, def.span);
- let tt_spec = NonterminalKind::TT;
+ let tt_spec = Some(NonterminalKind::TT);
// Parse the macro_rules! invocation
let (macro_rules, body) = match &def.kind {
TokenTree::Sequence(span, ref seq) => {
if seq.separator.is_none()
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
- TokenTree::MetaVarDecl(_, _, NonterminalKind::Vis) => true,
+ TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
TokenTree::Sequence(_, ref sub_seq) => {
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
// Now `last` holds the complete set of NT tokens that could
// end the sequence before SUFFIX. Check that every one works with `suffix`.
for token in &last.tokens {
- if let TokenTree::MetaVarDecl(_, name, kind) = *token {
+ if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token {
for next_token in &suffix_first.tokens {
match is_in_follow(next_token, kind) {
IsInFollow::Yes => {}
}
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
- if let mbe::TokenTree::MetaVarDecl(_, _, kind) = *tok {
+ if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
frag_can_be_followed_by_any(kind)
} else {
// (Non NT's can always be followed by anything in matchers.)
}
_ => IsInFollow::No(TOKENS),
},
- TokenTree::MetaVarDecl(_, _, NonterminalKind::Block) => IsInFollow::Yes,
+ TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
}
}
TokenTree::MetaVarDecl(
_,
_,
- NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path,
+ Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
) => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
}
match *tt {
mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token),
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
- mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
+ mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
+ mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
_ => panic!(
"{}",
"unexpected mbe::TokenTree::{Sequence or Delimited} \
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream;
-use rustc_ast::NodeId;
+use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{kw, Ident};
.emit();
token::NonterminalKind::Ident
});
- result.push(TokenTree::MetaVarDecl(span, ident, kind));
+ result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
continue;
}
_ => token.span,
}
tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
};
- sess.span_diagnostic.struct_span_err(span, "missing fragment specifier").emit();
- continue;
+ if node_id != DUMMY_NODE_ID {
+ // Macros loaded from other crates have dummy node ids.
+ sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id);
+ }
+ result.push(TokenTree::MetaVarDecl(span, ident, None));
}
// Not a metavar or no matchers allowed, so just return the tree
use rustc_ast::ptr::P;
use rustc_ast::token;
-use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
use rustc_ast::{self as ast, *};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability, ErrorReported};
let input = if item.pretty_printing_compatibility_hack() {
TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
} else {
- nt_to_tokenstream(&item, &ecx.sess.parse_sess, DUMMY_SP)
+ nt_to_tokenstream(
+ &item,
+ &ecx.sess.parse_sess,
+ DUMMY_SP,
+ CanSynthesizeMissingTokens::Yes,
+ )
};
let server = proc_macro_server::Rustc::new(ecx);
use rustc_ast as ast;
use rustc_ast::token;
-use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
+use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
+use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_errors::Diagnostic;
{
TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span))
} else {
- let stream = nt_to_tokenstream(&nt, sess, span);
+ let stream = nt_to_tokenstream(&nt, sess, span, CanSynthesizeMissingTokens::No);
TokenTree::Group(Group {
delimiter: Delimiter::None,
stream,
/// Allows patterns with concurrent by-move and by-ref bindings.
/// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
(accepted, move_ref_pattern, "1.48.0", Some(68354), None),
+ /// The smallest useful subset of `const_generics`.
+ (accepted, min_const_generics, "1.51.0", Some(74878), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
/// Allows calling `transmute` in const fn
(active, const_fn_transmute, "1.46.0", Some(53605), None),
- /// The smallest useful subset of `const_generics`.
- (active, min_const_generics, "1.47.0", Some(74878), None),
-
/// Allows `if let` guard in match arms.
(active, if_let_guard, "1.47.0", Some(51114), None),
/// Some features are not allowed to be used together at the same time, if
/// the two are present, produce an error.
-pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] =
- &[(sym::const_generics, sym::min_const_generics)];
+///
+/// Currently empty, but we will probably need this again in the future,
+/// so let's keep it in for now.
+pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[];
pub span: Span,
/// Either "`'a`", referring to a named lifetime definition,
- /// or "``" (i.e., `kw::Invalid`), for elision placeholders.
+ /// or "``" (i.e., `kw::Empty`), for elision placeholders.
///
/// HIR lowering inserts these placeholders in type paths that
/// refer to type definitions needing lifetime parameters,
// over the ids in increasing order. In principle it should not
// matter what order we visit things in, but in *practice* it
// does, because it can affect the order in which errors are
- // detected, which in turn can make compile-fail tests yield
+ // detected, which in turn can make UI tests yield
// slightly different results.
pub items: BTreeMap<HirId, Item<'hir>>,
//! In this code, we report errors on each `rustc_if_this_changed`
//! annotation. If a path exists in all cases, then we would report
//! "all path(s) exist". Otherwise, we report: "no path to `foo`" for
-//! each case where no path exists. `compile-fail` tests can then be
+//! each case where no path exists. `ui` tests can then be
//! used to check when paths exist or do not.
//!
//! The full form of the `rustc_if_this_changed` annotation is
// obviously it never weeds out ALL errors.
fn process_errors(
&self,
- errors: &Vec<RegionResolutionError<'tcx>>,
+ errors: &[RegionResolutionError<'tcx>],
) -> Vec<RegionResolutionError<'tcx>> {
debug!("process_errors()");
};
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
- errors.clone()
+ errors.to_owned()
} else {
errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
};
[segment]
if segment
.res
- .map(|res| match res {
- Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
- _ => false,
- })
+ .map(|res| matches!(res, Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)))
.unwrap_or(false) =>
{
self.types.push(path.span);
/// True for free regions other than `'static`.
pub fn is_free(&self, r: Region<'_>) -> bool {
- match *r {
- ty::ReEarlyBound(_) | ty::ReFree(_) => true,
- _ => false,
- }
+ matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_))
}
/// True if `r` is a free region or static of the sort that this
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
- match *b_data {
- VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
- _ => true,
- }
+ !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue)
});
}
}
}
VerifyBound::IsEmpty => {
- if let ty::ReEmpty(_) = min {
- true
- } else {
- false
- }
+ matches!(min, ty::ReEmpty(_))
}
VerifyBound::AnyBound(bs) => {
T: TypeFoldable<'tcx>,
{
if !value.needs_infer() {
- return value.clone(); // Avoid duplicated subst-folding.
+ return value; // Avoid duplicated subst-folding.
}
let mut r = resolve::OpportunisticVarResolver::new(self);
value.fold_with(&mut r)
pub enum ProjectionCacheEntry<'tcx> {
InProgress,
Ambiguous,
+ Recur,
Error,
NormalizedTy(NormalizedTy<'tcx>),
}
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
key, value
);
- let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value));
+ let mut map = self.map();
+ if let Some(ProjectionCacheEntry::Recur) = map.get(&key) {
+ debug!("Not overwriting Recur");
+ return;
+ }
+ let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
assert!(!fresh_key, "never started projecting `{:?}`", key);
}
assert!(!fresh, "never started projecting `{:?}`", key);
}
+ /// Indicates that while trying to normalize `key`, `key` was required to
+ /// be normalized again. Selection or evaluation should eventually report
+ /// an error here.
+ pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) {
+ let fresh = self.map().insert(key, ProjectionCacheEntry::Recur);
+ assert!(!fresh, "never started projecting `{:?}`", key);
+ }
+
/// Indicates that trying to normalize `key` resulted in
/// error.
pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
pub type Result<T> = result::Result<T, ErrorReported>;
/// Represents a compiler session.
+///
/// Can be used to run `rustc_interface` queries.
-/// Created by passing `Config` to `run_compiler`.
+/// Created by passing [`Config`] to [`run_compiler`].
pub struct Compiler {
pub(crate) sess: Lrc<Session>,
codegen_backend: Lrc<Box<dyn CodegenBackend>>,
use rustc_plugin_impl as plugin;
use rustc_resolve::{Resolver, ResolverArenas};
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode};
+use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
use rustc_session::Session;
/// harness if one is to be provided, injection of a dependency on the
/// standard library and prelude, and name resolution.
///
-/// Returns `None` if we're aborting after handling -W help.
+/// Returns [`None`] if we're aborting after handling -W help.
pub fn configure_and_expand(
sess: Lrc<Session>,
lint_store: Lrc<LintStore>,
ecx.check_unused_macros();
});
+ let mut missing_fragment_specifiers: Vec<_> = ecx
+ .sess
+ .parse_sess
+ .missing_fragment_specifiers
+ .borrow()
+ .iter()
+ .map(|(span, node_id)| (*span, *node_id))
+ .collect();
+ missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span);
+
+ let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
+
+ for (span, node_id) in missing_fragment_specifiers {
+ let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
+ let msg = "missing fragment specifier";
+ resolver.lint_buffer().buffer_lint(lint, node_id, span, msg);
+ }
if cfg!(windows) {
env::set_var("PATH", &old_path);
}
- let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
if recursion_limit_hit {
// If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
// with a large AST
// Avoid overwhelming user with errors if borrow checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids a
- // lot of annoying errors in the compile-fail tests (basically,
+ // lot of annoying errors in the ui tests (basically,
// lint warnings and so on -- kindck used to do this abort, but
// kindck is gone now). -nmatsakis
if sess.has_errors() {
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
});
+ // Don't run these test assertions when not doing codegen. Compiletest tries to build
+ // build-fail tests in check mode first and expects it to not give an error in that case.
+ if tcx.sess.opts.output_types.should_codegen() {
+ rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+ rustc_symbol_mangling::test::report_symbol_names(tcx);
+ }
+
+ tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
+ tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
+
+ // We assume that no queries are run past here. If there are new queries
+ // after this point, they'll show up as "<unknown>" in self-profiling data.
+ {
+ let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
+ tcx.alloc_self_profile_query_strings();
+ }
+
info!("Post-codegen\n{:?}", tcx.debug_stats());
if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
use std::rc::Rc;
/// Represent the result of a query.
-/// This result can be stolen with the `take` method and generated with the `compute` method.
+///
+/// This result can be stolen with the [`take`] method and generated with the [`compute`] method.
+///
+/// [`take`]: Self::take
+/// [`compute`]: Self::compute
pub struct Query<T> {
result: RefCell<Option<Result<T>>>,
}
// Don't do code generation if there were any errors
self.session().compile_status()?;
- // Hook for compile-fail tests.
+ // Hook for UI tests.
Self::check_for_rustc_errors_attr(tcx);
Ok(passes::start_codegen(&***self.codegen_backend(), tcx, &*outputs.peek()))
}
/// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
- /// to write compile-fail tests that actually test that compilation succeeds without reporting
+ /// to write UI tests that actually test that compilation succeeds without reporting
/// an error.
fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
let def_id = match tcx.entry_fn(LOCAL_CRATE) {
return Ok(());
}
+ let _timer = sess.prof.verbose_generic_activity("link_crate");
self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs)
}
}
if let ast::AssocItemKind::Fn(_, ref sig, _, _) = it.kind {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
- if ident.name == kw::Invalid {
+ if ident.name == kw::Empty {
cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
}
}
-const HAS_MIN_FEATURES: &[Symbol] = &[sym::const_generics, sym::specialization];
+const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
declare_lint! {
/// The `invalid_value` lint detects creating a value that is not valid,
}
}
+ #[track_caller]
pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
let target = match self.by_name.get(new_name) {
Some(&Id(lint_id)) => lint_id,
/// Check if a `DefId`'s path matches the given absolute type path usage.
///
- /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
+ /// Anonymous scopes such as `extern` imports are matched with `kw::Empty`;
/// inherent `impl` blocks are matched with the name of the type.
///
/// Instead of using this method, it is often preferable to instead use
use rustc_middle::hir::map::Map;
use rustc_middle::lint::LevelSource;
use rustc_middle::lint::LintDiagnosticBuilder;
-use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
+use rustc_middle::lint::{
+ struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet,
+};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::{builtin, Level, Lint, LintId};
};
for id in ids {
self.check_gated_lint(id, DUMMY_SP);
- let src = LintSource::CommandLine(lint_flag_val, orig_level);
+ let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
specs.insert(id, (level, src));
}
}
);
diag_builder.span_label(src.span(), "overruled by previous forbid");
match old_src {
- LintSource::Default => {
+ LintLevelSource::Default => {
diag_builder.note(&format!(
"`forbid` lint level is the default for {}",
id.to_string()
));
}
- LintSource::Node(_, forbid_source_span, reason) => {
+ LintLevelSource::Node(_, forbid_source_span, reason) => {
diag_builder.span_label(forbid_source_span, "`forbid` level set here");
if let Some(rationale) = reason {
diag_builder.note(&rationale.as_str());
}
}
- LintSource::CommandLine(_, _) => {
+ LintLevelSource::CommandLine(_, _) => {
diag_builder.note("`forbid` lint level was set on command line");
}
}
let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
match store.check_lint_name(&name.as_str(), tool_name) {
CheckLintNameResult::Ok(ids) => {
- let src = LintSource::Node(name, li.span(), reason);
+ let src = LintLevelSource::Node(name, li.span(), reason);
for &id in ids {
self.check_gated_lint(id, attr.span);
self.insert_spec(&mut specs, id, (level, src));
match result {
Ok(ids) => {
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
- let src = LintSource::Node(
+ let src = LintLevelSource::Node(
Symbol::intern(complete_name),
li.span(),
reason,
},
);
- let src = LintSource::Node(
+ let src = LintLevelSource::Node(
Symbol::intern(&new_lint_name),
li.span(),
reason,
}
let (lint_attr_name, lint_attr_span) = match *src {
- LintSource::Node(name, span, _) => (name, span),
+ LintLevelSource::Node(name, span, _) => (name, span),
_ => continue,
};
}
/// Find the lint level for a lint.
- pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) {
+ pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) {
self.sets.get_lint_level(lint, self.cur, None, self.sess)
}
UNUSED_MUT,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
- OVERLAPPING_PATTERNS,
UNUSED_MUST_USE,
UNUSED_UNSAFE,
PATH_STATEMENTS,
store.register_renamed("exceeding_bitshifts", "arithmetic_overflow");
store.register_renamed("redundant_semicolon", "redundant_semicolons");
store.register_renamed("intra_doc_link_resolution_failure", "broken_intra_doc_links");
+ store.register_renamed("overlapping_patterns", "overlapping_range_endpoints");
store.register_removed("unknown_features", "replaced by an error");
store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
store.register_removed("negate_unsigned", "cast a signed value instead");
impl EarlyLintPass for RedundantSemicolons {
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
- let mut after_item_stmt = false;
let mut seq = None;
for stmt in block.stmts.iter() {
match (&stmt.kind, &mut seq) {
(StmtKind::Empty, None) => seq = Some((stmt.span, false)),
(StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true),
- (_, seq) => {
- maybe_lint_redundant_semis(cx, seq, after_item_stmt);
- after_item_stmt = matches!(stmt.kind, StmtKind::Item(_));
- }
+ (_, seq) => maybe_lint_redundant_semis(cx, seq),
}
}
- maybe_lint_redundant_semis(cx, &mut seq, after_item_stmt);
+ maybe_lint_redundant_semis(cx, &mut seq);
}
}
-fn maybe_lint_redundant_semis(
- cx: &EarlyContext<'_>,
- seq: &mut Option<(Span, bool)>,
- after_item_stmt: bool,
-) {
+fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
if let Some((span, multiple)) = seq.take() {
// FIXME: Find a better way of ignoring the trailing
// semicolon from macro expansion
return;
}
- // FIXME: Lint on semicolons after item statements
- // once doing so doesn't break bootstrapping
- if after_item_stmt {
- return;
- }
-
cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
let (msg, rem) = if multiple {
("unnecessary trailing semicolons", "remove these semicolons")
}
declare_lint! {
- /// The `overlapping_patterns` lint detects `match` arms that have
- /// [range patterns] that overlap.
+ /// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that
+ /// overlap on their endpoints.
///
/// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns
///
///
/// ### Explanation
///
- /// It is likely a mistake to have range patterns in a match expression
- /// that overlap. Check that the beginning and end values are what you
- /// expect, and keep in mind that with `..=` the left and right bounds are
- /// inclusive.
- pub OVERLAPPING_PATTERNS,
+ /// It is likely a mistake to have range patterns in a match expression that overlap in this
+ /// way. Check that the beginning and end values are what you expect, and keep in mind that
+ /// with `..=` the left and right bounds are inclusive.
+ pub OVERLAPPING_RANGE_ENDPOINTS,
Warn,
- "detects overlapping patterns"
+ "detects range patterns with overlapping endpoints"
}
declare_lint! {
};
}
+declare_lint! {
+ /// The `missing_fragment_specifier` lint is issued when an unused pattern in a
+ /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not
+ /// followed by a fragment specifier (e.g. `:expr`).
+ ///
+ /// This warning can always be fixed by removing the unused pattern in the
+ /// `macro_rules!` macro definition.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// macro_rules! foo {
+ /// () => {};
+ /// ($name) => { };
+ /// }
+ ///
+ /// fn main() {
+ /// foo!();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// To fix this, remove the unused pattern from the `macro_rules!` macro definition:
+ ///
+ /// ```rust
+ /// macro_rules! foo {
+ /// () => {};
+ /// }
+ /// fn main() {
+ /// foo!();
+ /// }
+ /// ```
+ pub MISSING_FRAGMENT_SPECIFIER,
+ Deny,
+ "detects missing fragment specifiers in unused `macro_rules!` patterns",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
+ edition: None,
+ };
+}
+
declare_lint! {
/// The `late_bound_lifetime_arguments` lint detects generic lifetime
/// arguments in path segments with late bound lifetime parameters.
DEAD_CODE,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
- OVERLAPPING_PATTERNS,
+ OVERLAPPING_RANGE_ENDPOINTS,
BINDINGS_WITH_VARIANT_NAME,
UNUSED_MACROS,
WARNINGS,
CONST_ITEM_MUTATION,
SAFE_PACKED_BORROWS,
PATTERNS_IN_FNS_WITHOUT_BODY,
+ MISSING_FRAGMENT_SPECIFIER,
LATE_BOUND_LIFETIME_ARGUMENTS,
ORDER_DEPENDENT_TRAIT_OBJECTS,
COHERENCE_LEAK_CHECK,
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{
- braced, parenthesized, parse_macro_input, AttrStyle, Attribute, Block, Error, Expr, Ident,
- ReturnType, Token, Type,
+ braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error,
+ Expr, Ident, ReturnType, Token, Type,
};
mod kw {
if desc.is_some() {
panic!("duplicate modifier `desc` for query `{}`", query.name);
}
+ // If there are no doc-comments, give at least some idea of what
+ // it does by showing the query description.
+ if query.doc_comments.is_empty() {
+ use ::syn::*;
+ let mut list = list.iter();
+ let format_str: String = match list.next() {
+ Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
+ lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
+ }
+ _ => panic!("Expected a string literal"),
+ };
+ let mut fmt_fragments = format_str.split("{}");
+ let mut doc_string = fmt_fragments.next().unwrap().to_string();
+ list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
+ |(tts, next_fmt_fragment)| {
+ use ::core::fmt::Write;
+ write!(
+ &mut doc_string,
+ " `{}` {}",
+ tts.to_string().replace(" . ", "."),
+ next_fmt_fragment,
+ )
+ .unwrap();
+ },
+ );
+ let doc_string = format!(
+ "[query description - consider adding a doc-comment!] {}",
+ doc_string
+ );
+ let comment = parse_quote! {
+ #[doc = #doc_string]
+ };
+ query.doc_comments.push(comment);
+ }
desc = Some((tcx, list));
}
QueryModifier::FatalCycle => {
/// format!("Expected a point greater than ({x}, {y})", x = self.x, y = self.y)
/// ```
/// This function builds the entire call to format!.
- fn build_format(&self, input: &String, span: proc_macro2::Span) -> proc_macro2::TokenStream {
+ fn build_format(&self, input: &str, span: proc_macro2::Span) -> proc_macro2::TokenStream {
// This set is used later to generate the final format string. To keep builds reproducible,
// the iteration order needs to be deterministic, hence why we use a BTreeSet here instead
// of a HashSet.
impl Collector<'tcx> {
fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
- if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) {
+ if lib.name.as_ref().map(|&s| s == kw::Empty).unwrap_or(false) {
match span {
Some(span) => {
struct_span_err!(
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{DefPathHash, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
mod dep_node;
type DepKind = DepKind;
type StableHashingContext = StableHashingContext<'tcx>;
- fn register_reused_dep_path_hash(&self, hash: DefPathHash) {
+ fn register_reused_dep_node(&self, dep_node: &DepNode) {
if let Some(cache) = self.queries.on_disk_cache.as_ref() {
- cache.register_reused_dep_path_hash(*self, hash)
+ cache.register_reused_dep_node(*self, dep_node)
}
}
impl MaybeFnLike for hir::Item<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::ItemKind::Fn(..) => true,
- _ => false,
- }
+ matches!(self.kind, hir::ItemKind::Fn(..))
}
}
impl MaybeFnLike for hir::ImplItem<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::ImplItemKind::Fn(..) => true,
- _ => false,
- }
+ matches!(self.kind, hir::ImplItemKind::Fn(..))
}
}
impl MaybeFnLike for hir::TraitItem<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true,
- _ => false,
- }
+ matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)))
}
}
impl MaybeFnLike for hir::Expr<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::ExprKind::Closure(..) => true,
- _ => false,
- }
+ matches!(self.kind, hir::ExprKind::Closure(..))
}
}
pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
self.body(id).params.iter().map(|arg| match arg.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
- _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP),
+ _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP),
})
}
base: PlaceBase,
projections: Vec<Projection<'tcx>>,
) -> PlaceWithHirId<'tcx> {
- PlaceWithHirId {
- hir_id: hir_id,
- place: Place { base_ty: base_ty, base: base, projections: projections },
- }
+ PlaceWithHirId { hir_id, place: Place { base_ty, base, projections } }
}
}
//! - **MIR.** The "mid-level (M) intermediate representation (IR)" is
//! defined in the `mir` module. This module contains only the
//! *definition* of the MIR; the passes that transform and operate
-//! on MIR are found in `librustc_mir` crate.
+//! on MIR are found in `rustc_mir` crate.
//! - **Types.** The internal representation of types used in rustc is
//! defined in the `ty` module. This includes the **type context**
//! (or `tcx`), which is the central context during most of
/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
-pub enum LintSource {
+pub enum LintLevelSource {
/// Lint is at the default level as declared
/// in rustc or a plugin.
Default,
Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),
/// Lint level was set by a command-line flag.
- /// The provided `Level` is the level specified on the command line -
- /// the actual level may be lower due to `--cap-lints`
+ /// The provided `Level` is the level specified on the command line.
+ /// (The actual level may be lower due to `--cap-lints`.)
CommandLine(Symbol, Level),
}
-impl LintSource {
+impl LintLevelSource {
pub fn name(&self) -> Symbol {
match *self {
- LintSource::Default => symbol::kw::Default,
- LintSource::Node(name, _, _) => name,
- LintSource::CommandLine(name, _) => name,
+ LintLevelSource::Default => symbol::kw::Default,
+ LintLevelSource::Node(name, _, _) => name,
+ LintLevelSource::CommandLine(name, _) => name,
}
}
pub fn span(&self) -> Span {
match *self {
- LintSource::Default => DUMMY_SP,
- LintSource::Node(_, span, _) => span,
- LintSource::CommandLine(_, _) => DUMMY_SP,
+ LintLevelSource::Default => DUMMY_SP,
+ LintLevelSource::Node(_, span, _) => span,
+ LintLevelSource::CommandLine(_, _) => DUMMY_SP,
}
}
}
-pub type LevelSource = (Level, LintSource);
+/// A tuple of a lint level and its source.
+pub type LevelSource = (Level, LintLevelSource);
pub struct LintLevelSets {
pub list: Vec<LintSet>,
id: LintId,
mut idx: u32,
aux: Option<&FxHashMap<LintId, LevelSource>>,
- ) -> (Option<Level>, LintSource) {
+ ) -> (Option<Level>, LintLevelSource) {
if let Some(specs) = aux {
if let Some(&(level, src)) = specs.get(&id) {
return (Some(level), src);
if let Some(&(level, src)) = specs.get(&id) {
return (Some(level), src);
}
- return (None, LintSource::Default);
+ return (None, LintLevelSource::Default);
}
LintSet::Node { ref specs, parent } => {
if let Some(&(level, src)) = specs.get(&id) {
sess: &'s Session,
lint: &'static Lint,
level: Level,
- src: LintSource,
+ src: LintLevelSource,
span: Option<MultiSpan>,
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
) {
sess: &'s Session,
lint: &'static Lint,
level: Level,
- src: LintSource,
+ src: LintLevelSource,
span: Option<MultiSpan>,
decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
) {
let name = lint.name_lower();
match src {
- LintSource::Default => {
+ LintLevelSource::Default => {
sess.diag_note_once(
&mut err,
DiagnosticMessageId::from(lint),
&format!("`#[{}({})]` on by default", level.as_str(), name),
);
}
- LintSource::CommandLine(lint_flag_val, orig_level) => {
+ LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
let flag = match orig_level {
Level::Warn => "-W",
Level::Deny => "-D",
);
}
}
- LintSource::Node(lint_attr_name, src, reason) => {
+ LintLevelSource::Node(lint_attr_name, src, reason) => {
if let Some(rationale) = reason {
err.note(&rationale.as_str());
}
use std::fmt;
use std::hash::Hash;
-// Accessibility levels, sorted in ascending order
+/// Represents the levels of accessibility an item can have.
+///
+/// The variants are sorted in ascending order of accessibility.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
pub enum AccessLevel {
/// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
/// public, then type `T` is reachable. Its values can be obtained by other crates
/// even if the type itself is not nameable.
Reachable,
- /// Public items + items accessible to other crates with help of `pub use` re-exports
+ /// Public items + items accessible to other crates with the help of `pub use` re-exports.
Exported,
- /// Items accessible to other crates directly, without help of re-exports
+ /// Items accessible to other crates directly, without the help of re-exports.
Public,
}
-// Accessibility levels for reachable HIR nodes
+/// Holds a map of accessibility levels for reachable HIR nodes.
#[derive(Clone)]
pub struct AccessLevels<Id = HirId> {
pub map: FxHashMap<Id, AccessLevel>,
pub struct YieldData {
/// The `Span` of the yield.
pub span: Span,
- /// The number of expressions and patterns appearing before the `yield` in the body plus one.
+ /// The number of expressions and patterns appearing before the `yield` in the body, plus one.
pub expr_and_pat_count: usize,
pub source: hir::YieldSource,
}
}
/// Checks whether the given scope contains a `yield`. If so,
- /// returns `Some((span, expr_count))` with the span of a yield we found and
- /// the number of expressions and patterns appearing before the `yield` in the body + 1.
- /// If there a are multiple yields in a scope, the one with the highest number is returned.
+ /// returns `Some(YieldData)`. If not, returns `None`.
pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
self.yield_in_scope.get(&scope).cloned()
}
}
pub fn is_counter(&self) -> bool {
- match self {
- Self::Counter { .. } => true,
- _ => false,
- }
+ matches!(self, Self::Counter { .. })
}
pub fn is_expression(&self) -> bool {
- match self {
- Self::Expression { .. } => true,
- _ => false,
- }
+ matches!(self, Self::Expression { .. })
}
pub fn is_unreachable(&self) -> bool {
--- /dev/null
+use rustc_data_structures::graph::{
+ self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors,
+};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_serialize as serialize;
+
+/// Helper type to cache the result of `graph::is_cyclic`.
+#[derive(Clone, Debug)]
+pub(super) struct GraphIsCyclicCache {
+ cache: OnceCell<bool>,
+}
+
+impl GraphIsCyclicCache {
+ #[inline]
+ pub(super) fn new() -> Self {
+ GraphIsCyclicCache { cache: OnceCell::new() }
+ }
+
+ pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool
+ where
+ G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
+ {
+ *self.cache.get_or_init(|| graph::is_cyclic(graph))
+ }
+
+ /// Invalidates the cache.
+ #[inline]
+ pub(super) fn invalidate(&mut self) {
+ // Invalidating the cache requires mutating the MIR, which in turn requires a unique
+ // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
+ // callers of `invalidate` have a unique reference to the MIR and thus to the
+ // cache. This means we never need to do synchronization when `invalidate` is called,
+ // we can simply reinitialize the `OnceCell`.
+ self.cache = OnceCell::new();
+ }
+}
+
+impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache {
+ #[inline]
+ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+ serialize::Encodable::encode(&(), s)
+ }
+}
+
+impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache {
+ #[inline]
+ fn decode(d: &mut D) -> Result<Self, D::Error> {
+ serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+ }
+}
+
+impl<CTX> HashStable<CTX> for GraphIsCyclicCache {
+ #[inline]
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+TrivialTypeFoldableAndLiftImpls! {
+ GraphIsCyclicCache,
+}
use std::slice;
use std::{iter, mem, option};
+use self::graph_cyclic_cache::GraphIsCyclicCache;
use self::predecessors::{PredecessorCache, Predecessors};
pub use self::query::*;
pub mod abstract_const;
pub mod coverage;
+mod graph_cyclic_cache;
pub mod interpret;
pub mod mono;
mod predecessors;
pub is_polymorphic: bool,
predecessor_cache: PredecessorCache,
+ is_cyclic: GraphIsCyclicCache,
}
impl<'tcx> Body<'tcx> {
required_consts: Vec::new(),
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
+ is_cyclic: GraphIsCyclicCache::new(),
};
body.is_polymorphic = body.has_param_types_or_consts();
body
var_debug_info: Vec::new(),
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
+ is_cyclic: GraphIsCyclicCache::new(),
};
body.is_polymorphic = body.has_param_types_or_consts();
body
#[inline]
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
// Because the user could mutate basic block terminators via this reference, we need to
- // invalidate the predecessor cache.
+ // invalidate the caches.
//
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
- // invalidate the predecessor cache.
+ // invalidate the caches.
self.predecessor_cache.invalidate();
+ self.is_cyclic.invalidate();
&mut self.basic_blocks
}
&mut self,
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
self.predecessor_cache.invalidate();
+ self.is_cyclic.invalidate();
(&mut self.basic_blocks, &mut self.local_decls)
}
&mut Vec<VarDebugInfo<'tcx>>,
) {
self.predecessor_cache.invalidate();
+ self.is_cyclic.invalidate();
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
}
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
/// `START_BLOCK`.
pub fn is_cfg_cyclic(&self) -> bool {
- graph::is_cyclic(self)
+ self.is_cyclic.is_cyclic(self)
}
#[inline]
let mut index = 0;
for statement in statements {
- let location = Location { block: block, statement_index: index };
+ let location = Location { block, statement_index: index };
self.visit_statement(statement, location);
index += 1;
}
if let Some(terminator) = terminator {
- let location = Location { block: block, statement_index: index };
+ let location = Location { block, statement_index: index };
self.visit_terminator(terminator, location);
}
}
desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
}
- query impl_trait_ref(key: DefId) -> Option<ty::TraitRef<'tcx>> {
- desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) }
+ /// Given an `impl_id`, return the trait it implements.
+ /// Return `None` if this is an inherent impl.
+ query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
+ desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
}
- query impl_polarity(key: DefId) -> ty::ImplPolarity {
- desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) }
+ query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
+ desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
}
query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
}
TypeChecking {
- query trait_of_item(def_id: DefId) -> Option<DefId> {
- desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) }
+ /// Given an `associated_item`, find the trait it belongs to.
+ /// Return `None` if the `DefId` is not an associated item.
+ query trait_of_item(associated_item: DefId) -> Option<DefId> {
+ desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
}
}
}
TypeChecking {
- query all_local_trait_impls(key: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
+ /// Return all `impl` blocks in the current crate.
+ ///
+ /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number.
+ /// Passing in any other crate will cause an ICE.
+ ///
+ /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
+ query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
desc { "local trait impls" }
}
- query trait_impls_of(key: DefId) -> ty::trait_def::TraitImpls {
+
+ /// Given a trait `trait_id`, return all known `impl` blocks.
+ query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
storage(ArenaCacheSelector<'tcx>)
- desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) }
+ desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
}
- query specialization_graph_of(key: DefId) -> specialization_graph::Graph {
+
+ query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
storage(ArenaCacheSelector<'tcx>)
- desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) }
+ desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
cache_on_disk_if { true }
}
- query object_safety_violations(key: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
- desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
+ query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
+ desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
}
/// Gets the ParameterEnvironment for a given item; this environment
/// type-checking etc, and it does not normalize specializable
/// associated types. This is almost always what you want,
/// unless you are doing MIR optimizations, in which case you
+ /// might want to use `reveal_all()` method to change modes.
query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
}
}
TypeChecking {
+ /// Given a crate and a trait, look up all impls of that trait in the crate.
+ /// Return `(impl_id, self_ty)`.
query implementations_of_trait(_: (CrateNum, DefId))
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up implementations of a trait in a crate" }
}
+
+ /// Given a crate, look up all trait impls in that crate.
+ /// Return `(impl_id, self_ty)`.
query all_trait_implementations(_: CrateNum)
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up all (?) trait implementations" }
use crate::hir::exports::ExportMap;
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
-use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource};
+use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
use crate::middle;
use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata};
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
#[inline]
pub fn lazy_normalization(self) -> bool {
let features = self.features();
- // Note: We do not enable lazy normalization for `features.min_const_generics`.
+ // Note: We do not enable lazy normalization for `min_const_generics`.
features.const_generics || features.lazy_normalization_consts
}
self,
lint: &'static Lint,
mut id: hir::HirId,
- ) -> (Level, LintSource) {
+ ) -> (Level, LintLevelSource) {
let sets = self.lint_levels(LOCAL_CRATE);
loop {
if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
// We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
- let callable_scope = match body_owner {
- Some(
+ let callable_scope = matches!(body_owner, Some(
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
| hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
- ) => true,
- _ => false,
- };
+ ));
let impl_comparison = matches!(
cause_code,
ObligationCauseCode::CompareImplMethodObligation { .. }
/// If A and B are DefIds in the `DefIdForest`, and A is a descendant
/// of B, then only B will be in `root_ids`.
/// We use a `SmallVec` here because (for its use for caching inhabitedness)
- /// its rare that this will contain even two IDs.
+ /// it's rare that this will contain even two IDs.
root_ids: SmallVec<[DefId; 1]>,
}
let layout = tcx.intern_layout(Layout {
variants: Variants::Multiple {
- tag: tag,
+ tag,
tag_encoding: TagEncoding::Direct,
tag_field: tag_index,
variants,
/// This means we can use pointer for both
/// equality comparisons and hashing.
///
-/// Unlike slices, The types contained in `List` are expected to be `Copy`
+/// Unlike slices, the types contained in `List` are expected to be `Copy`
/// and iterating over a `List` returns `T` instead of a reference.
///
/// Note: `Slice` was already taken by the `Ty`.
+//! Defines how the compiler represents types internally.
+//!
+//! Two important entities in this module are:
+//!
+//! - [`rustc_middle::ty::Ty`], used to represent the semantics of a type.
+//! - [`rustc_middle::ty::TyCtxt`], the central data structure in the compiler.
+//!
+//! For more information, see ["The `ty` module: representing types"] in the ructc-dev-guide.
+//!
+//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
+
// ignore-tidy-filelength
pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor};
pub use self::AssocItemContainer::*;
/// which cause cycle errors.
///
/// ```rust
-/// #![feature(const_generics)]
-///
/// struct A;
/// impl A {
/// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] }
// FIXME(eddyb) `name` should never be empty, but it
// currently is for `extern { ... }` "foreign modules".
let name = disambiguated_data.data.name();
- if name != DefPathDataName::Named(kw::Invalid) {
+ if name != DefPathDataName::Named(kw::Empty) {
if !self.empty_path {
write!(self, "::")?;
}
match *region {
ty::ReEarlyBound(ref data) => {
- data.name != kw::Invalid && data.name != kw::UnderscoreLifetime
+ data.name != kw::Empty && data.name != kw::UnderscoreLifetime
}
ty::ReLateBound(_, ty::BoundRegion { kind: br })
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
if let ty::BrNamed(_, name) = br {
- if name != kw::Invalid && name != kw::UnderscoreLifetime {
+ if name != kw::Empty && name != kw::UnderscoreLifetime {
return true;
}
}
// `explain_region()` or `note_and_explain_region()`.
match *region {
ty::ReEarlyBound(ref data) => {
- if data.name != kw::Invalid {
+ if data.name != kw::Empty {
p!(write("{}", data.name));
return Ok(self);
}
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
if let ty::BrNamed(_, name) = br {
- if name != kw::Invalid && name != kw::UnderscoreLifetime {
+ if name != kw::Empty && name != kw::UnderscoreLifetime {
p!(write("{}", name));
return Ok(self);
}
-use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
+use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use crate::mir::{self, interpret};
use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder};
(file_to_file_index, file_index_to_stable_id)
};
+ // Register any dep nodes that we reused from the previous session,
+ // but didn't `DepNode::construct` in this session. This ensures
+ // that their `DefPathHash` to `RawDefId` mappings are registered
+ // in 'latest_foreign_def_path_hashes' if necessary, since that
+ // normally happens in `DepNode::construct`.
+ tcx.dep_graph.register_reused_dep_nodes(tcx);
+
// Load everything into memory so we can write it out to the on-disk
// cache. The vast majority of cacheable query results should already
// be in memory, so this should be a cheap operation.
.insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() });
}
- /// If the given `hash` still exists in the current compilation,
- /// calls `store_foreign_def_id` with its current `DefId`.
+ /// If the given `dep_node`'s hash still exists in the current compilation,
+ /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it.
///
/// Normally, `store_foreign_def_id_hash` can be called directly by
/// the dependency graph when we construct a `DepNode`. However,
/// session, we only have the `DefPathHash` available. This method is used
/// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written
/// out for usage in the next compilation session.
- pub fn register_reused_dep_path_hash(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) {
- // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
- // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
- // changed in the current compilation session (e.g. we've added/removed crates,
- // or added/removed definitions before/after the target definition).
- if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
- self.store_foreign_def_id_hash(def_id, hash);
+ pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
+ // For reused dep nodes, we only need to store the mapping if the node
+ // is one whose query key we can reconstruct from the hash. We use the
+ // mapping to aid that reconstruction in the next session. While we also
+ // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`,
+ // they're already registered during `DefId` encoding.
+ if dep_node.kind.can_reconstruct_query_key() {
+ let hash = DefPathHash(dep_node.hash.into());
+
+ // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
+ // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
+ // changed in the current compilation session (e.g. we've added/removed crates,
+ // or added/removed definitions before/after the target definition).
+ if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
+ if !def_id.is_local() {
+ self.store_foreign_def_id_hash(def_id, hash);
+ }
+ }
}
}
//- DECODING -------------------------------------------------------------------
-/// A decoder that can read from the incr. comp. cache. It is similar to the one
+/// A decoder that can read from the incremental compilation cache. It is similar to the one
/// we use for crate metadata decoding in that it can rebase spans and eventually
/// will also handle things that contain `Ty` instances.
crate struct CacheDecoder<'a, 'tcx> {
//- ENCODING -------------------------------------------------------------------
-/// An encoder that can write the incr. comp. cache.
+/// An encoder that can write to the incremental compilation cache.
struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
tcx: TyCtxt<'tcx>,
encoder: &'a mut E,
impl TyKind<'tcx> {
#[inline]
pub fn is_primitive(&self) -> bool {
- match self {
- Bool | Char | Int(_) | Uint(_) | Float(_) => true,
- _ => false,
- }
+ matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_))
}
/// Get the article ("a" or "an") to use with this type.
pub name: Symbol,
}
+/// A **ty**pe **v**ariable **ID**.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
pub struct TyVid {
pub index: u32,
}
+/// A **`const`** **v**ariable **ID**.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
pub struct ConstVid<'tcx> {
pub index: u32,
pub phantom: PhantomData<&'tcx ()>,
}
+/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
pub struct IntVid {
pub index: u32,
}
+/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
pub struct FloatVid {
pub index: u32,
}
rustc_index::newtype_index! {
+ /// A **region** (lifetime) **v**ariable **ID**.
pub struct RegionVid {
DEBUG_FORMAT = custom,
}
}
}
+/// A placeholder for a type that hasn't been inferred yet.
+///
+/// E.g., if we have an empty array (`[]`), then we create a fresh
+/// type variable for the element type since we won't know until it's
+/// used what the element type is supposed to be.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable)]
pub enum InferTy {
+ /// A type variable.
TyVar(TyVid),
+ /// An integral type variable (`{integer}`).
+ ///
+ /// These are created when the compiler sees an integer literal like
+ /// `1` that could be several different types (`u8`, `i32`, `u32`, etc.).
+ /// We don't know until it's used what type it's supposed to be, so
+ /// we create a fresh type variable.
IntVar(IntVid),
+ /// A floating-point type variable (`{float}`).
+ ///
+ /// These are created when the compiler sees an float literal like
+ /// `1.0` that could be either an `f32` or an `f64`.
+ /// We don't know until it's used what type it's supposed to be, so
+ /// we create a fresh type variable.
FloatVar(FloatVid),
- /// A `FreshTy` is one that is generated as a replacement for an
- /// unbound type variable. This is convenient for caching etc. See
- /// `infer::freshen` for more details.
+ /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
+ /// for an unbound type variable. This is convenient for caching etc. See
+ /// `rustc_infer::infer::freshen` for more details.
+ ///
+ /// Compare with [`TyVar`][Self::TyVar].
FreshTy(u32),
+ /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar].
FreshIntTy(u32),
+ /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar].
FreshFloatTy(u32),
}
}
pub fn is_late_bound(&self) -> bool {
- match *self {
- ty::ReLateBound(..) => true,
- _ => false,
- }
+ matches!(*self, ty::ReLateBound(..))
}
pub fn is_placeholder(&self) -> bool {
- match *self {
- ty::RePlaceholder(..) => true,
- _ => false,
- }
+ matches!(*self, ty::RePlaceholder(..))
}
pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool {
opt_span_bug_fmt(Some(span), args, Location::caller());
}
+#[track_caller]
fn opt_span_bug_fmt<S: Into<MultiSpan>>(
span: Option<S>,
args: fmt::Arguments<'_>,
&self,
def_id: DefId,
target_place: PlaceRef<'tcx>,
- places: &Vec<Operand<'tcx>>,
+ places: &[Operand<'tcx>],
) -> Option<(Span, Option<GeneratorKind>, Span)> {
debug!(
"closure_span: def_id={:?} target_place={:?} places={:?}",
}
impl LocalUseMap {
- crate fn build(
- live_locals: &Vec<Local>,
- elements: &RegionValueElements,
- body: &Body<'_>,
- ) -> Self {
+ crate fn build(live_locals: &[Local], elements: &RegionValueElements, body: &Body<'_>) -> Self {
let nones = IndexVec::from_elem_n(None, body.local_decls.len());
let mut local_use_map = LocalUseMap {
first_def_at: nones.clone(),
Ok(mplace) => {
// Since evaluation had no errors, valiate the resulting constant:
let validation = try {
- // FIXME do not validate promoteds until a decision on
- // https://github.com/rust-lang/rust/issues/67465 and
- // https://github.com/rust-lang/rust/issues/67534 is made.
- // Promoteds can contain unexpected `UnsafeCell` and reference `static`s, but their
- // otherwise restricted form ensures that this is still sound. We just lose the
- // extra safety net of some of the dynamic checks. They can also contain invalid
- // values, but since we do not usually check intermediate results of a computation
- // for validity, it might be surprising to do that here.
- if cid.promoted.is_none() {
- let mut ref_tracking = RefTracking::new(mplace);
- let mut inner = false;
- while let Some((mplace, path)) = ref_tracking.todo.pop() {
- let mode = match tcx.static_mutability(cid.instance.def_id()) {
- Some(_) => CtfeValidationMode::Regular, // a `static`
- None => CtfeValidationMode::Const { inner },
- };
- ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
- inner = true;
- }
+ let mut ref_tracking = RefTracking::new(mplace);
+ let mut inner = false;
+ while let Some((mplace, path)) = ref_tracking.todo.pop() {
+ let mode = match tcx.static_mutability(cid.instance.def_id()) {
+ Some(_) if cid.promoted.is_some() => {
+ // Promoteds in statics are allowed to point to statics.
+ CtfeValidationMode::Const { inner, allow_static_ptrs: true }
+ }
+ Some(_) => CtfeValidationMode::Regular, // a `static`
+ None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
+ };
+ ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
+ inner = true;
}
};
if let Err(error) = validation {
}
sym::min_align_of_val | sym::size_of_val => {
- let place = self.deref_operand(args[0])?;
+ // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
+ // dereferencable!
+ let place = self.ref_to_mplace(self.read_immediate(args[0])?)?;
let (size, align) = self
- .size_and_align_of(place.meta, place.layout)?
+ .size_and_align_of_mplace(place)?
.ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
let result = match intrinsic_name {
let result = Scalar::from_uint(truncated_bits, layout.size);
self.write_scalar(result, dest)?;
}
+ sym::copy | sym::copy_nonoverlapping => {
+ let elem_ty = instance.substs.type_at(0);
+ let elem_layout = self.layout_of(elem_ty)?;
+ let count = self.read_scalar(args[2])?.to_machine_usize(self)?;
+ let elem_align = elem_layout.align.abi;
+
+ let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
+ err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
+ })?;
+ let src = self.read_scalar(args[0])?.check_init()?;
+ let src = self.memory.check_ptr_access(src, size, elem_align)?;
+ let dest = self.read_scalar(args[1])?.check_init()?;
+ let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
+
+ if let (Some(src), Some(dest)) = (src, dest) {
+ self.memory.copy(
+ src,
+ dest,
+ size,
+ intrinsic_name == sym::copy_nonoverlapping,
+ )?;
+ }
+ }
sym::offset => {
let ptr = self.read_scalar(args[0])?.check_init()?;
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
pub enum CtfeValidationMode {
/// Regular validation, nothing special happening.
Regular,
- /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed
- /// to the top-level const allocation).
- /// Being an inner allocation makes a difference because the top-level allocation of a `const`
- /// is copied for each use, but the inner allocations are implicitly shared.
- Const { inner: bool },
+ /// Validation of a `const`.
+ /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const
+ /// allocation). Being an inner allocation makes a difference because the top-level allocation
+ /// of a `const` is copied for each use, but the inner allocations are implicitly shared.
+ /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics).
+ Const { inner: bool, allow_static_ptrs: bool },
}
/// State for tracking recursive validation of references
}
/// Format a path
-fn write_path(out: &mut String, path: &Vec<PathElem>) {
+fn write_path(out: &mut String, path: &[PathElem]) {
use self::PathElem::*;
for elem in path.iter() {
}
// Make sure this is dereferenceable and all.
let size_and_align = try_validation!(
- self.ecx.size_and_align_of(place.meta, place.layout),
+ self.ecx.size_and_align_of_mplace(place),
self.path,
err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
);
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
assert!(!self.ecx.tcx.is_thread_local_static(did));
assert!(self.ecx.tcx.is_static(did));
- if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
+ if matches!(
+ self.ctfe_mode,
+ Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. })
+ ) {
// See const_eval::machine::MemoryExtra::can_access_statics for why
// this check is so important.
// This check is reachable when the const just referenced the static,
// Sanity check: `builtin_deref` does not know any pointers that are not primitive.
assert!(op.layout.ty.builtin_deref(true).is_none());
- // Special check preventing `UnsafeCell` in constants
+ // Special check preventing `UnsafeCell` in the inner part of constants
if let Some(def) = op.layout.ty.ty_adt_def() {
- if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true }))
+ if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. }))
&& Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type()
{
throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
/// message for subsequent debugging.
fn make_bcb_counters(
&mut self,
- coverage_spans: &Vec<CoverageSpan>,
+ coverage_spans: &[CoverageSpan],
) -> Result<Vec<CoverageKind>, Error> {
debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
let num_bcbs = self.basic_coverage_blocks.num_nodes();
fn choose_preferred_expression_branch(
&self,
traversal: &TraverseCoverageGraphWithLoops,
- branches: &Vec<BcbBranch>,
+ branches: &[BcbBranch],
) -> BcbBranch {
let branch_needs_a_counter =
|branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
fn find_some_reloop_branch(
&self,
traversal: &TraverseCoverageGraphWithLoops,
- branches: &Vec<BcbBranch>,
+ branches: &[BcbBranch],
) -> Option<BcbBranch> {
let branch_needs_a_counter =
|branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
};
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::DefId;
+use rustc_span::source_map::SourceMap;
use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol};
/// A simple error message wrapper for `coverage::Error`s.
self.mir_body,
counter_kind,
self.bcb_leader_bb(bcb),
- Some(make_code_region(file_name, &self.source_file, span, body_span)),
+ Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)),
);
}
}
/// Convert the Span into its file name, start line and column, and end line and column
fn make_code_region(
+ source_map: &SourceMap,
file_name: Symbol,
source_file: &Lrc<SourceFile>,
span: Span,
} else {
source_file.lookup_file_pos(span.hi())
};
+ let start_line = source_map.doctest_offset_line(&source_file.name, start_line);
+ let end_line = source_map.doctest_offset_line(&source_file.name, end_line);
CodeRegion {
file_name,
start_line: start_line as u32,
&self,
def_id: DefId,
substs_ref: SubstsRef<'tcx>,
- args: &Vec<Operand<'tcx>>,
+ args: &[Operand<'tcx>],
source_info: SourceInfo,
) {
let param_env = self.tcx.param_env(def_id);
.unwrap_or(None)
}
- fn nth_arg_span(&self, args: &Vec<Operand<'tcx>>, n: usize) -> Span {
+ fn nth_arg_span(&self, args: &[Operand<'tcx>], n: usize) -> Span {
match &args[n] {
Operand::Copy(place) | Operand::Move(place) => {
self.body.local_decls[place.local].source_info.span
optimization_finder.optimizations
};
- // Then carry out those optimizations.
- MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
+ if !optimizations.is_empty() {
+ // Then carry out those optimizations.
+ MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
+ }
}
}
}
}
- self.super_rvalue(rvalue, location)
+ // We do not call super_rvalue as we are not interested in any other parts of the tree
}
}
self.find_unneeded_equality_comparison(rvalue, location);
- self.super_rvalue(rvalue, location)
+ // We do not call super_rvalue as we are not interested in any other parts of the tree
}
}
unneeded_equality_comparison: FxHashMap<Location, Operand<'tcx>>,
unneeded_deref: FxHashMap<Location, Place<'tcx>>,
}
+
+impl<'tcx> OptimizationList<'tcx> {
+ fn is_empty(&self) -> bool {
+ match self {
+ OptimizationList {
+ and_stars,
+ arrays_lengths,
+ unneeded_equality_comparison,
+ unneeded_deref,
+ } => {
+ and_stars.is_empty()
+ && arrays_lengths.is_empty()
+ && unneeded_equality_comparison.is_empty()
+ && unneeded_deref.is_empty()
+ }
+ }
+ }
+}
impl TempState {
pub fn is_promotable(&self) -> bool {
debug!("is_promotable: self={:?}", self);
- matches!(self, TempState::Defined { .. } )
+ matches!(self, TempState::Defined { .. })
}
}
let statement = &self.body[loc.block].statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
- match kind {
- BorrowKind::Shared | BorrowKind::Mut { .. } => {}
-
- // FIXME(eddyb) these aren't promoted here but *could*
- // be promoted as part of a larger value because
- // `validate_rvalue` doesn't check them, need to
- // figure out what is the intended behavior.
- BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
- }
-
// We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway).
self.validate_local(place.local)?;
+ // The reference operation itself must be promotable.
+ // (Needs to come after `validate_local` to avoid ICEs.)
+ self.validate_ref(*kind, place)?;
+
+ // We do not check all the projections (they do not get promoted anyway),
+ // but we do stay away from promoting anything involving a dereference.
if place.projection.contains(&ProjectionElem::Deref) {
return Err(Unpromotable);
}
- if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
- return Err(Unpromotable);
- }
- // FIXME(eddyb) this duplicates part of `validate_rvalue`.
- let has_mut_interior =
- self.qualif_local::<qualifs::HasMutInterior>(place.local);
- if has_mut_interior {
+ // We cannot promote things that need dropping, since the promoted value
+ // would not get dropped.
+ if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}
- if let BorrowKind::Mut { .. } = kind {
- let ty = place.ty(self.body, self.tcx).ty;
-
- // In theory, any zero-sized value could be borrowed
- // mutably without consequences. However, only &mut []
- // is allowed right now.
- if let ty::Array(_, len) = ty.kind() {
- match len.try_eval_usize(self.tcx, self.param_env) {
- Some(0) => {}
- _ => return Err(Unpromotable),
- }
- } else {
- return Err(Unpromotable);
- }
- }
-
Ok(())
}
_ => bug!(),
}
}
- fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
- match *rvalue {
- Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
- let operand_ty = operand.ty(self.body, self.tcx);
- let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
- if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
- // ptr-to-int casts are not possible in consts and thus not promotable
+ fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
+ match kind {
+ // Reject these borrow types just to be safe.
+ // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
+ BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
+
+ BorrowKind::Shared => {
+ let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
+ if has_mut_interior {
return Err(Unpromotable);
}
}
- Rvalue::BinaryOp(op, ref lhs, _) => {
- if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
- assert!(
- op == BinOp::Eq
- || op == BinOp::Ne
- || op == BinOp::Le
- || op == BinOp::Lt
- || op == BinOp::Ge
- || op == BinOp::Gt
- || op == BinOp::Offset
- );
+ BorrowKind::Mut { .. } => {
+ let ty = place.ty(self.body, self.tcx).ty;
- // raw pointer operations are not allowed inside consts and thus not promotable
+ // In theory, any zero-sized value could be borrowed
+ // mutably without consequences. However, only &mut []
+ // is allowed right now.
+ if let ty::Array(_, len) = ty.kind() {
+ match len.try_eval_usize(self.tcx, self.param_env) {
+ Some(0) => {}
+ _ => return Err(Unpromotable),
+ }
+ } else {
return Err(Unpromotable);
}
}
-
- Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable),
-
- // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
- _ => {}
}
+ Ok(())
+ }
+
+ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
match rvalue {
- Rvalue::ThreadLocalRef(_) => Err(Unpromotable),
+ Rvalue::Use(operand)
+ | Rvalue::Repeat(operand, _)
+ | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => {
+ self.validate_operand(operand)?;
+ }
- Rvalue::NullaryOp(..) => Ok(()),
+ Rvalue::Discriminant(place) | Rvalue::Len(place) => {
+ self.validate_place(place.as_ref())?
+ }
- Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref()),
+ Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
- Rvalue::Use(operand)
- | Rvalue::Repeat(operand, _)
- | Rvalue::UnaryOp(_, operand)
- | Rvalue::Cast(_, operand, _) => self.validate_operand(operand),
+ Rvalue::Cast(kind, operand, cast_ty) => {
+ if matches!(kind, CastKind::Misc) {
+ let operand_ty = operand.ty(self.body, self.tcx);
+ let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
+ let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+ if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
+ // ptr-to-int casts are not possible in consts and thus not promotable
+ return Err(Unpromotable);
+ }
+ // int-to-ptr casts are fine, they just use the integer value at pointer type.
+ }
+
+ self.validate_operand(operand)?;
+ }
+
+ Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
+ let op = *op;
+ if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
+ // raw pointer operations are not allowed inside consts and thus not promotable
+ assert!(matches!(
+ op,
+ BinOp::Eq
+ | BinOp::Ne
+ | BinOp::Le
+ | BinOp::Lt
+ | BinOp::Ge
+ | BinOp::Gt
+ | BinOp::Offset
+ ));
+ return Err(Unpromotable);
+ }
+
+ match op {
+ // FIXME: reject operations that can fail -- namely, division and modulo.
+ BinOp::Eq
+ | BinOp::Ne
+ | BinOp::Le
+ | BinOp::Lt
+ | BinOp::Ge
+ | BinOp::Gt
+ | BinOp::Offset
+ | BinOp::Add
+ | BinOp::Sub
+ | BinOp::Mul
+ | BinOp::Div
+ | BinOp::Rem
+ | BinOp::BitXor
+ | BinOp::BitAnd
+ | BinOp::BitOr
+ | BinOp::Shl
+ | BinOp::Shr => {}
+ }
- Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
self.validate_operand(lhs)?;
- self.validate_operand(rhs)
+ self.validate_operand(rhs)?;
}
+ Rvalue::NullaryOp(op, _) => match op {
+ NullOp::Box => return Err(Unpromotable),
+ NullOp::SizeOf => {}
+ },
+
Rvalue::AddressOf(_, place) => {
// We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
// no problem, only using it is.
});
}
}
- Err(Unpromotable)
+ return Err(Unpromotable);
}
Rvalue::Ref(_, kind, place) => {
- if let BorrowKind::Mut { .. } = kind {
- let ty = place.ty(self.body, self.tcx).ty;
-
- // In theory, any zero-sized value could be borrowed
- // mutably without consequences. However, only &mut []
- // is allowed right now.
- if let ty::Array(_, len) = ty.kind() {
- match len.try_eval_usize(self.tcx, self.param_env) {
- Some(0) => {}
- _ => return Err(Unpromotable),
- }
- } else {
- return Err(Unpromotable);
- }
- }
-
// Special-case reborrows to be more like a copy of the reference.
- let mut place = place.as_ref();
- if let [proj_base @ .., ProjectionElem::Deref] = &place.projection {
- let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+ let mut place_simplified = place.as_ref();
+ if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection {
+ let base_ty =
+ Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.kind() {
- place = PlaceRef { local: place.local, projection: proj_base };
+ place_simplified =
+ PlaceRef { local: place_simplified.local, projection: proj_base };
}
}
- self.validate_place(place)?;
-
- let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
- if has_mut_interior {
- return Err(Unpromotable);
- }
+ self.validate_place(place_simplified)?;
- Ok(())
+ // Check that the reference is fine (using the original place!).
+ // (Needs to come after `validate_place` to avoid ICEs.)
+ self.validate_ref(*kind, place)?;
}
- Rvalue::Aggregate(_, ref operands) => {
+ Rvalue::Aggregate(_, operands) => {
for o in operands {
self.validate_operand(o)?;
}
-
- Ok(())
}
}
+
+ Ok(())
}
fn validate_call(
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
-/// putting code into a compile-fail test and using `rustc_peek` to
+/// putting code into an UI test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
return false;
}
- // Verify the assigment chain consists of the form b = a; c = b; d = c; etc...
+ // Verify the assignment chain consists of the form b = a; c = b; d = c; etc...
if opt_info.field_tmp_assignments.is_empty() {
trace!("NO: no assignments found");
return false;
err.span_label(
new_loan_span,
format!(
- "mutable borrow starts here in previous \
- iteration of loop{}",
- opt_via
+ "{}{} was mutably borrowed here in the previous iteration of the loop{}",
+ desc,
+ via(opt_via),
+ opt_via,
),
);
if let Some(old_load_end_span) = old_load_end_span {
};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor};
use rustc_target::abi::Size;
use std::ops::ControlFlow;
}
}
+fn use_verbose(ty: &&TyS<'tcx>) -> bool {
+ match ty.kind() {
+ ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false,
+ // Unit type
+ ty::Tuple(g_args) if g_args.is_empty() => false,
+ ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty())),
+ ty::Array(ty, _) => use_verbose(ty),
+ ty::FnDef(..) => false,
+ _ => true,
+ }
+}
+
impl Visitor<'tcx> for ExtraComments<'tcx> {
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
self.super_constant(constant, location);
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
self.super_const(constant);
let ty::Const { ty, val, .. } = constant;
- match ty.kind() {
- ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {}
- // Unit type
- ty::Tuple(tys) if tys.is_empty() => {}
- ty::FnDef(..) => {}
- _ => {
- self.push("ty::Const");
- self.push(&format!("+ ty: {:?}", ty));
- self.push(&format!("+ val: {:?}", val));
- }
+ if use_verbose(ty) {
+ self.push("ty::Const");
+ self.push(&format!("+ ty: {:?}", ty));
+ self.push(&format!("+ val: {:?}", val));
}
}
/// part of a path that is captued by a closure. We stop applying projections once we see the first
/// projection that isn't captured by a closure.
fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
- mir_projections: &Vec<PlaceElem<'tcx>>,
+ mir_projections: &[PlaceElem<'tcx>],
) -> Vec<HirProjectionKind> {
let mut hir_projections = Vec::new();
/// list are being applied to the same root variable.
fn is_ancestor_or_same_capture(
proj_possible_ancestor: &Vec<HirProjectionKind>,
- proj_capture: &Vec<HirProjectionKind>,
+ proj_capture: &[HirProjectionKind],
) -> bool {
// We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
// Therefore we can't just check if all projections are same in the zipped iterator below.
typeck_results: &'a ty::TypeckResults<'tcx>,
var_hir_id: HirId,
closure_def_id: DefId,
- projections: &Vec<PlaceElem<'tcx>>,
+ projections: &[PlaceElem<'tcx>],
) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?;
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
- let expr_is_block_or_scope = match expr.kind {
- ExprKind::Block { .. } => true,
- ExprKind::Scope { .. } => true,
- _ => false,
- };
+ let expr_is_block_or_scope = matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
let schedule_drop = move |this: &mut Self| {
if let Some(drop_scope) = scope {
let mut mutability = Mutability::Not;
// FIXME(project-rfc-2229#8): Store more precise information
- let mut name = kw::Invalid;
+ let mut name = kw::Empty;
if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
name = ident.name;
-//! This module provides functions to deconstruct and reconstruct patterns into a constructor
-//! applied to some fields. This is used by the `_match` module to compute pattern
-//! usefulness/exhaustiveness.
+//! [`super::usefulness`] explains most of what is happening in this file. As explained there,
+//! values and patterns are made from constructors applied to fields. This file defines a
+//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert
+//! them from/to patterns.
+//!
+//! There's one idea that is not detailed in [`super::usefulness`] because the details are not
+//! needed there: _constructor splitting_.
+//!
+//! # Constructor splitting
+//!
+//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn
+//! with all the value constructors that are covered by `c`, and compute usefulness for each.
+//! Instead of listing all those constructors (which is intractable), we group those value
+//! constructors together as much as possible. Example:
+//!
+//! ```
+//! match (0, false) {
+//! (0 ..=100, true) => {} // `p_1`
+//! (50..=150, false) => {} // `p_2`
+//! (0 ..=200, _) => {} // `q`
+//! }
+//! ```
+//!
+//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more
+//! clever: `0` and `1` for example will match the exact same rows, and return equivalent
+//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4
+//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely
+//! more tractable.
+//!
+//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors
+//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'`
+//! return an equivalent set of witnesses after specializing and computing usefulness.
+//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ
+//! in their first element.
+//!
+//! We usually also ask that the `c'` together cover all of the original `c`. However we allow
+//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses
+//! is empty of not. We use this in the wildcard `_` case.
+//!
+//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for
+//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
+//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]; for slices, see
+//! [`SplitVarLenSlice`].
+
use self::Constructor::*;
use self::SliceKind::*;
use smallvec::{smallvec, SmallVec};
use std::cmp::{self, max, min, Ordering};
-use std::iter::IntoIterator;
+use std::iter::{once, IntoIterator};
use std::ops::RangeInclusive;
/// An inclusive interval, used for precise integer exhaustiveness checking.
// 2 -------- // 2 -------
let (lo, hi) = self.boundaries();
let (other_lo, other_hi) = other.boundaries();
- lo == other_hi || hi == other_lo
+ (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton()
}
fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
}
- /// For exhaustive integer matching, some constructors are grouped within other constructors
- /// (namely integer typed values are grouped within ranges). However, when specialising these
- /// constructors, we want to be specialising for the underlying constructors (the integers), not
- /// the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would
- /// mean creating a separate constructor for every single value in the range, which is clearly
- /// impractical. However, observe that for some ranges of integers, the specialisation will be
- /// identical across all values in that range (i.e., there are equivalence classes of ranges of
- /// constructors based on their `U(S(c, P), S(c, p))` outcome). These classes are grouped by
- /// the patterns that apply to them (in the matrix `P`). We can split the range whenever the
- /// patterns that apply to that range (specifically: the patterns that *intersect* with that range)
- /// change.
- /// Our solution, therefore, is to split the range constructor into subranges at every single point
- /// the group of intersecting patterns changes (using the method described below).
- /// And voilà ! We're testing precisely those ranges that we need to, without any exhaustive matching
- /// on actual integers. The nice thing about this is that the number of subranges is linear in the
- /// number of rows in the matrix (i.e., the number of cases in the `match` statement), so we don't
- /// need to be worried about matching over gargantuan ranges.
- ///
- /// Essentially, given the first column of a matrix representing ranges, looking like the following:
- ///
- /// |------| |----------| |-------| ||
- /// |-------| |-------| |----| ||
- /// |---------|
- ///
- /// We split the ranges up into equivalence classes so the ranges are no longer overlapping:
- ///
- /// |--|--|||-||||--||---|||-------| |-|||| ||
- ///
- /// The logic for determining how to split the ranges is fairly straightforward: we calculate
- /// boundaries for each interval range, sort them, then create constructors for each new interval
- /// between every pair of boundary points. (This essentially sums up to performing the intuitive
- /// merging operation depicted above.)
- fn split<'p, 'tcx>(
+ /// Lint on likely incorrect range patterns (#63987)
+ pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>(
&self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- hir_id: Option<HirId>,
- ) -> SmallVec<[Constructor<'tcx>; 1]> {
- /// Represents a border between 2 integers. Because the intervals spanning borders
- /// must be able to cover every integer, we need to be able to represent
- /// 2^128 + 1 such borders.
- #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
- enum Border {
- JustBefore(u128),
- AfterMax,
+ pcx: PatCtxt<'_, '_, 'tcx>,
+ ctors: impl Iterator<Item = (&'a Constructor<'tcx>, Span)>,
+ column_count: usize,
+ hir_id: HirId,
+ ) {
+ if self.is_singleton() {
+ return;
}
- // A function for extracting the borders of an integer interval.
- fn range_borders(r: IntRange) -> impl Iterator<Item = Border> {
- let (lo, hi) = r.range.into_inner();
- let from = Border::JustBefore(lo);
- let to = match hi.checked_add(1) {
- Some(m) => Border::JustBefore(m),
- None => Border::AfterMax,
- };
- vec![from, to].into_iter()
+ if column_count != 1 {
+ // FIXME: for now, only check for overlapping ranges on simple range
+ // patterns. Otherwise with the current logic the following is detected
+ // as overlapping:
+ // ```
+ // match (0u8, true) {
+ // (0 ..= 125, false) => {}
+ // (125 ..= 255, true) => {}
+ // _ => {}
+ // }
+ // ```
+ return;
}
- // Collect the span and range of all the intersecting ranges to lint on likely
- // incorrect range patterns. (#63987)
- let mut overlaps = vec![];
- let row_len = pcx.matrix.column_count().unwrap_or(0);
- // `borders` is the set of borders between equivalence classes: each equivalence
- // class lies between 2 borders.
- let row_borders = pcx
- .matrix
- .head_ctors_and_spans(pcx.cx)
+ let overlaps: Vec<_> = ctors
.filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)))
- .filter_map(|(range, span)| {
- let intersection = self.intersection(&range);
- let should_lint = self.suspicious_intersection(&range);
- if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
- // FIXME: for now, only check for overlapping ranges on simple range
- // patterns. Otherwise with the current logic the following is detected
- // as overlapping:
- // ```
- // match (0u8, true) {
- // (0 ..= 125, false) => {}
- // (125 ..= 255, true) => {}
- // _ => {}
- // }
- // ```
- overlaps.push((range.clone(), span));
- }
- intersection
- })
- .flat_map(range_borders);
- let self_borders = range_borders(self.clone());
- let mut borders: Vec<_> = row_borders.chain(self_borders).collect();
- borders.sort_unstable();
-
- self.lint_overlapping_patterns(pcx, hir_id, overlaps);
-
- // We're going to iterate through every adjacent pair of borders, making sure that
- // each represents an interval of nonnegative length, and convert each such
- // interval into a constructor.
- borders
- .array_windows()
- .filter_map(|&pair| match pair {
- [Border::JustBefore(n), Border::JustBefore(m)] => {
- if n < m {
- Some(n..=(m - 1))
- } else {
- None
- }
- }
- [Border::JustBefore(n), Border::AfterMax] => Some(n..=u128::MAX),
- [Border::AfterMax, _] => None,
- })
- .map(|range| IntRange { range })
- .map(IntRange)
- .collect()
- }
+ .filter(|(range, _)| self.suspicious_intersection(range))
+ .map(|(range, span)| (self.intersection(&range).unwrap(), span))
+ .collect();
- fn lint_overlapping_patterns(
- &self,
- pcx: PatCtxt<'_, '_, '_>,
- hir_id: Option<HirId>,
- overlaps: Vec<(IntRange, Span)>,
- ) {
- if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
+ if !overlaps.is_empty() {
pcx.cx.tcx.struct_span_lint_hir(
- lint::builtin::OVERLAPPING_PATTERNS,
+ lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
hir_id,
pcx.span,
|lint| {
- let mut err = lint.build("multiple patterns covering the same range");
- err.span_label(pcx.span, "overlapping patterns");
+ let mut err = lint.build("multiple patterns overlap on their endpoints");
for (int_range, span) in overlaps {
- // Use the real type for user display of the ranges:
err.span_label(
span,
&format!(
- "this range overlaps on `{}`",
- int_range.to_pat(pcx.cx.tcx, pcx.ty),
+ "this range overlaps on `{}`...",
+ int_range.to_pat(pcx.cx.tcx, pcx.ty)
),
);
}
+ err.span_label(pcx.span, "... with this range");
+ err.note("you likely meant to write mutually exclusive ranges");
err.emit();
},
);
}
}
+/// Represents a border between 2 integers. Because the intervals spanning borders must be able to
+/// cover every integer, we need to be able to represent 2^128 + 1 such borders.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+enum IntBorder {
+ JustBefore(u128),
+ AfterMax,
+}
+
+/// A range of integers that is partitioned into disjoint subranges. This does constructor
+/// splitting for integer ranges as explained at the top of the file.
+///
+/// This is fed multiple ranges, and returns an output that covers the input, but is split so that
+/// the only intersections between an output range and a seen range are inclusions. No output range
+/// straddles the boundary of one of the inputs.
+///
+/// The following input:
+/// ```
+/// |-------------------------| // `self`
+/// |------| |----------| |----|
+/// |-------| |-------|
+/// ```
+/// would be iterated over as follows:
+/// ```
+/// ||---|--||-|---|---|---|--|
+/// ```
+#[derive(Debug, Clone)]
+struct SplitIntRange {
+ /// The range we are splitting
+ range: IntRange,
+ /// The borders of ranges we have seen. They are all contained within `range`. This is kept
+ /// sorted.
+ borders: Vec<IntBorder>,
+}
+
+impl SplitIntRange {
+ fn new(range: IntRange) -> Self {
+ SplitIntRange { range, borders: Vec::new() }
+ }
+
+ /// Internal use
+ fn to_borders(r: IntRange) -> [IntBorder; 2] {
+ use IntBorder::*;
+ let (lo, hi) = r.boundaries();
+ let lo = JustBefore(lo);
+ let hi = match hi.checked_add(1) {
+ Some(m) => JustBefore(m),
+ None => AfterMax,
+ };
+ [lo, hi]
+ }
+
+ /// Add ranges relative to which we split.
+ fn split(&mut self, ranges: impl Iterator<Item = IntRange>) {
+ let this_range = &self.range;
+ let included_ranges = ranges.filter_map(|r| this_range.intersection(&r));
+ let included_borders = included_ranges.flat_map(|r| {
+ let borders = Self::to_borders(r);
+ once(borders[0]).chain(once(borders[1]))
+ });
+ self.borders.extend(included_borders);
+ self.borders.sort_unstable();
+ }
+
+ /// Iterate over the contained ranges.
+ fn iter<'a>(&'a self) -> impl Iterator<Item = IntRange> + Captures<'a> {
+ use IntBorder::*;
+
+ let self_range = Self::to_borders(self.range.clone());
+ // Start with the start of the range.
+ let mut prev_border = self_range[0];
+ self.borders
+ .iter()
+ .copied()
+ // End with the end of the range.
+ .chain(once(self_range[1]))
+ // List pairs of adjacent borders.
+ .map(move |border| {
+ let ret = (prev_border, border);
+ prev_border = border;
+ ret
+ })
+ // Skip duplicates.
+ .filter(|(prev_border, border)| prev_border != border)
+ // Finally, convert to ranges.
+ .map(|(prev_border, border)| {
+ let range = match (prev_border, border) {
+ (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1),
+ (JustBefore(n), AfterMax) => n..=u128::MAX,
+ _ => unreachable!(), // Ruled out by the sorting and filtering we did
+ };
+ IntRange { range }
+ })
+ }
+}
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum SliceKind {
/// Patterns of length `n` (`[x, y]`).
self.kind.arity()
}
- /// The exhaustiveness-checking paper does not include any details on
- /// checking variable-length slice patterns. However, they may be
- /// matched by an infinite collection of fixed-length array patterns.
- ///
- /// Checking the infinite set directly would take an infinite amount
- /// of time. However, it turns out that for each finite set of
- /// patterns `P`, all sufficiently large array lengths are equivalent:
- ///
- /// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
- /// to exactly the subset `Pₜ` of `P` can be transformed to a slice
- /// `sₘ` for each sufficiently-large length `m` that applies to exactly
- /// the same subset of `P`.
- ///
- /// Because of that, each witness for reachability-checking of one
- /// of the sufficiently-large lengths can be transformed to an
- /// equally-valid witness of any other length, so we only have
- /// to check slices of the "minimal sufficiently-large length"
- /// and less.
- ///
- /// Note that the fact that there is a *single* `sₘ` for each `m`
- /// not depending on the specific pattern in `P` is important: if
- /// you look at the pair of patterns
- /// `[true, ..]`
- /// `[.., false]`
- /// Then any slice of length ≥1 that matches one of these two
- /// patterns can be trivially turned to a slice of any
- /// other length ≥1 that matches them and vice-versa,
- /// but the slice of length 2 `[false, true]` that matches neither
- /// of these patterns can't be turned to a slice from length 1 that
- /// matches neither of these patterns, so we have to consider
- /// slices from length 2 there.
- ///
- /// Now, to see that that length exists and find it, observe that slice
- /// patterns are either "fixed-length" patterns (`[_, _, _]`) or
- /// "variable-length" patterns (`[_, .., _]`).
- ///
- /// For fixed-length patterns, all slices with lengths *longer* than
- /// the pattern's length have the same outcome (of not matching), so
- /// as long as `L` is greater than the pattern's length we can pick
- /// any `sₘ` from that length and get the same result.
- ///
- /// For variable-length patterns, the situation is more complicated,
- /// because as seen above the precise value of `sₘ` matters.
- ///
- /// However, for each variable-length pattern `p` with a prefix of length
- /// `plâ‚š` and suffix of length `slâ‚š`, only the first `plâ‚š` and the last
- /// `slâ‚š` elements are examined.
- ///
- /// Therefore, as long as `L` is positive (to avoid concerns about empty
- /// types), all elements after the maximum prefix length and before
- /// the maximum suffix length are not examined by any variable-length
- /// pattern, and therefore can be added/removed without affecting
- /// them - creating equivalent patterns from any sufficiently-large
- /// length.
- ///
- /// Of course, if fixed-length patterns exist, we must be sure
- /// that our length is large enough to miss them all, so
- /// we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
- ///
- /// for example, with the above pair of patterns, all elements
- /// but the first and last can be added/removed, so any
- /// witness of length ≥2 (say, `[false, false, true]`) can be
- /// turned to a witness from any other length ≥2.
- fn split<'p, 'tcx>(self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
- let (self_prefix, self_suffix) = match self.kind {
- VarLen(self_prefix, self_suffix) => (self_prefix, self_suffix),
- _ => return smallvec![Slice(self)],
- };
+ /// See `Constructor::is_covered_by`
+ fn is_covered_by(self, other: Self) -> bool {
+ other.kind.covers_length(self.arity())
+ }
+}
+
+/// This computes constructor splitting for variable-length slices, as explained at the top of the
+/// file.
+///
+/// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, _,
+/// _, y] | ...`. The corresponding value constructors are fixed-length array constructors above a
+/// given minimum length. We obviously can't list this infinitude of constructors. Thankfully,
+/// it turns out that for each finite set of slice patterns, all sufficiently large array lengths
+/// are equivalent.
+///
+/// Let's look at an example, where we are trying to split the last pattern:
+/// ```
+/// match x {
+/// [true, true, ..] => {}
+/// [.., false, false] => {}
+/// [..] => {}
+/// }
+/// ```
+/// Here are the results of specialization for the first few lengths:
+/// ```
+/// // length 0
+/// [] => {}
+/// // length 1
+/// [_] => {}
+/// // length 2
+/// [true, true] => {}
+/// [false, false] => {}
+/// [_, _] => {}
+/// // length 3
+/// [true, true, _ ] => {}
+/// [_, false, false] => {}
+/// [_, _, _ ] => {}
+/// // length 4
+/// [true, true, _, _ ] => {}
+/// [_, _, false, false] => {}
+/// [_, _, _, _ ] => {}
+/// // length 5
+/// [true, true, _, _, _ ] => {}
+/// [_, _, _, false, false] => {}
+/// [_, _, _, _, _ ] => {}
+/// ```
+///
+/// If we went above length 5, we would simply be inserting more columns full of wildcards in the
+/// middle. This means that the set of witnesses for length `l >= 5` if equivalent to the set for
+/// any other `l' >= 5`: simply add or remove wildcards in the middle to convert between them.
+///
+/// This applies to any set of slice patterns: there will be a length `L` above which all lengths
+/// behave the same. This is exactly what we need for constructor splitting. Therefore a
+/// variable-length slice can be split into a variable-length slice of minimal length `L`, and many
+/// fixed-length slices of lengths `< L`.
+///
+/// For each variable-length pattern `p` with a prefix of length `plâ‚š` and suffix of length `slâ‚š`,
+/// only the first `plâ‚š` and the last `slâ‚š` elements are examined. Therefore, as long as `L` is
+/// positive (to avoid concerns about empty types), all elements after the maximum prefix length
+/// and before the maximum suffix length are not examined by any variable-length pattern, and
+/// therefore can be added/removed without affecting them - creating equivalent patterns from any
+/// sufficiently-large length.
+///
+/// Of course, if fixed-length patterns exist, we must be sure that our length is large enough to
+/// miss them all, so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
+///
+/// `max_slice` below will be made to have arity `L`.
+#[derive(Debug)]
+struct SplitVarLenSlice {
+ /// If the type is an array, this is its size.
+ array_len: Option<u64>,
+ /// The arity of the input slice.
+ arity: u64,
+ /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L`
+ /// described above.
+ max_slice: SliceKind,
+}
- let head_ctors = pcx.matrix.head_ctors(pcx.cx).filter(|c| !c.is_wildcard());
+impl SplitVarLenSlice {
+ fn new(prefix: u64, suffix: u64, array_len: Option<u64>) -> Self {
+ SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) }
+ }
- let mut max_prefix_len = self_prefix;
- let mut max_suffix_len = self_suffix;
+ /// Pass a set of slices relative to which to split this one.
+ fn split(&mut self, slices: impl Iterator<Item = SliceKind>) {
+ let (max_prefix_len, max_suffix_len) = match &mut self.max_slice {
+ VarLen(prefix, suffix) => (prefix, suffix),
+ FixedLen(_) => return, // No need to split
+ };
+ // We grow `self.max_slice` to be larger than all slices encountered, as described above.
+ // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that
+ // `L = max_prefix_len + max_suffix_len`.
let mut max_fixed_len = 0;
-
- for ctor in head_ctors {
- if let Slice(slice) = ctor {
- match slice.kind {
- FixedLen(len) => {
- max_fixed_len = cmp::max(max_fixed_len, len);
- }
- VarLen(prefix, suffix) => {
- max_prefix_len = cmp::max(max_prefix_len, prefix);
- max_suffix_len = cmp::max(max_suffix_len, suffix);
- }
+ for slice in slices {
+ match slice {
+ FixedLen(len) => {
+ max_fixed_len = cmp::max(max_fixed_len, len);
+ }
+ VarLen(prefix, suffix) => {
+ *max_prefix_len = cmp::max(*max_prefix_len, prefix);
+ *max_suffix_len = cmp::max(*max_suffix_len, suffix);
}
- } else {
- bug!("unexpected ctor for slice type: {:?}", ctor);
}
}
-
- // For diagnostics, we keep the prefix and suffix lengths separate, so in the case
- // where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly,
- // so that `L = max_prefix_len + max_suffix_len`.
- if max_fixed_len + 1 >= max_prefix_len + max_suffix_len {
+ // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and
+ // suffix separate.
+ if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len {
// The subtraction can't overflow thanks to the above check.
- // The new `max_prefix_len` is also guaranteed to be larger than its previous
- // value.
- max_prefix_len = max_fixed_len + 1 - max_suffix_len;
+ // The new `max_prefix_len` is larger than its previous value.
+ *max_prefix_len = max_fixed_len + 1 - *max_suffix_len;
}
- let final_slice = VarLen(max_prefix_len, max_suffix_len);
- let final_slice = Slice::new(self.array_len, final_slice);
+ // We cap the arity of `max_slice` at the array size.
match self.array_len {
- Some(_) => smallvec![Slice(final_slice)],
- None => {
- // `self` originally covered the range `(self.arity()..infinity)`. We split that
- // range into two: lengths smaller than `final_slice.arity()` are treated
- // independently as fixed-lengths slices, and lengths above are captured by
- // `final_slice`.
- let smaller_lengths = (self.arity()..final_slice.arity()).map(FixedLen);
- smaller_lengths
- .map(|kind| Slice::new(self.array_len, kind))
- .chain(Some(final_slice))
- .map(Slice)
- .collect()
- }
+ Some(len) if self.max_slice.arity() >= len => self.max_slice = FixedLen(len),
+ _ => {}
}
}
- /// See `Constructor::is_covered_by`
- fn is_covered_by(self, other: Self) -> bool {
- other.kind.covers_length(self.arity())
+ /// Iterate over the partition of this slice.
+ fn iter<'a>(&'a self) -> impl Iterator<Item = Slice> + Captures<'a> {
+ let smaller_lengths = match self.array_len {
+ // The only admissible fixed-length slice is one of the array size. Whether `max_slice`
+ // is fixed-length or variable-length, it will be the only relevant slice to output
+ // here.
+ Some(_) => (0..0), // empty range
+ // We cover all arities in the range `(self.arity..infinity)`. We split that range into
+ // two: lengths smaller than `max_slice.arity()` are treated independently as
+ // fixed-lengths slices, and lengths above are captured by `max_slice`.
+ None => self.arity..self.max_slice.arity(),
+ };
+ smaller_lengths
+ .map(FixedLen)
+ .chain(once(self.max_slice))
+ .map(move |kind| Slice::new(self.array_len, kind))
}
}
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used
/// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
NonExhaustive,
+ /// Stands for constructors that are not seen in the matrix, as explained in the documentation
+ /// for [`SplitWildcard`].
+ Missing,
/// Wildcard pattern.
Wildcard,
}
/// This function may discard some irrelevant constructors if this preserves behavior and
/// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the
/// matrix, unless all of them are.
- ///
- /// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want
- /// to lint for overlapping ranges.
- pub(super) fn split<'p>(
+ pub(super) fn split<'a>(
&self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- hir_id: Option<HirId>,
- ) -> SmallVec<[Self; 1]> {
- debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
+ pcx: PatCtxt<'_, '_, 'tcx>,
+ ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
+ ) -> SmallVec<[Self; 1]>
+ where
+ 'tcx: 'a,
+ {
+ debug!("Constructor::split({:#?})", self);
match self {
- Wildcard => Constructor::split_wildcard(pcx),
+ Wildcard => {
+ let mut split_wildcard = SplitWildcard::new(pcx);
+ split_wildcard.split(pcx, ctors);
+ split_wildcard.into_ctors(pcx)
+ }
// Fast-track if the range is trivial. In particular, we don't do the overlapping
// ranges check.
- IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx, hir_id),
- Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
+ IntRange(ctor_range) if !ctor_range.is_singleton() => {
+ let mut split_range = SplitIntRange::new(ctor_range.clone());
+ let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range());
+ split_range.split(int_ranges.cloned());
+ split_range.iter().map(IntRange).collect()
+ }
+ &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => {
+ let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len);
+ let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind);
+ split_self.split(slices);
+ split_self.iter().map(Slice).collect()
+ }
// Any other constructor can be used unchanged.
_ => smallvec![self.clone()],
}
}
- /// For wildcards, there are two groups of constructors: there are the constructors actually
- /// present in the matrix (`head_ctors`), and the constructors not present (`missing_ctors`).
- /// Two constructors that are not in the matrix will either both be caught (by a wildcard), or
- /// both not be caught. Therefore we can keep the missing constructors grouped together.
- fn split_wildcard<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> {
- // Missing constructors are those that are not matched by any non-wildcard patterns in the
- // current column. We only fully construct them on-demand, because they're rarely used and
- // can be big.
- let missing_ctors = MissingConstructors::new(pcx);
- if missing_ctors.is_empty(pcx) {
- // All the constructors are present in the matrix, so we just go through them all.
- // We must also split them first.
- missing_ctors.all_ctors
- } else {
- // Some constructors are missing, thus we can specialize with the wildcard constructor,
- // which will stand for those constructors that are missing, and behaves like any of
- // them.
- smallvec![Wildcard]
- }
- }
-
/// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
/// For the simple cases, this is simply checking for equality. For the "grouped" constructors,
/// this checks for inclusion.
match (self, other) {
// Wildcards cover anything
(_, Wildcard) => true,
- // Wildcards are only covered by wildcards
- (Wildcard, _) => false,
+ // The missing ctors are not covered by anything in the matrix except wildcards.
+ (Missing | Wildcard, _) => false,
(Single, Single) => true,
(Variant(self_id), Variant(other_id)) => self_id == other_id,
.any(|other| slice.is_covered_by(other)),
// This constructor is never covered by anything else
NonExhaustive => false,
- Str(..) | FloatRange(..) | Opaque | Wildcard => {
+ Str(..) | FloatRange(..) | Opaque | Missing | Wildcard => {
span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
}
}
}
}
-/// This determines the set of all possible constructors of a pattern matching
-/// values of type `left_ty`. For vectors, this would normally be an infinite set
-/// but is instead bounded by the maximum fixed length of slice patterns in
-/// the column of patterns being analyzed.
+/// A wildcard constructor that we split relative to the constructors in the matrix, as explained
+/// at the top of the file.
///
-/// We make sure to omit constructors that are statically impossible. E.g., for
-/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
-/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
-/// `cx.is_uninhabited()`).
-fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tcx>> {
- debug!("all_constructors({:?})", pcx.ty);
- let cx = pcx.cx;
- let make_range = |start, end| {
- IntRange(
- // `unwrap()` is ok because we know the type is an integer.
- IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(),
- )
- };
- match pcx.ty.kind() {
- ty::Bool => vec![make_range(0, 1)],
- ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
- let len = len.eval_usize(cx.tcx, cx.param_env);
- if len != 0 && cx.is_uninhabited(sub_ty) {
- vec![]
- } else {
- vec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
- }
- }
- // Treat arrays of a constant but unknown length like slices.
- ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
- let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
- vec![Slice(Slice::new(None, kind))]
- }
- ty::Adt(def, substs) if def.is_enum() => {
- // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
- // additional "unknown" constructor.
- // There is no point in enumerating all possible variants, because the user can't
- // actually match against them all themselves. So we always return only the fictitious
- // constructor.
- // E.g., in an example like:
- //
- // ```
- // let err: io::ErrorKind = ...;
- // match err {
- // io::ErrorKind::NotFound => {},
- // }
- // ```
- //
- // we don't want to show every possible IO error, but instead have only `_` as the
- // witness.
- let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
-
- // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
- // as though it had an "unknown" constructor to avoid exposing its emptiness. The
- // exception is if the pattern is at the top level, because we want empty matches to be
- // considered exhaustive.
- let is_secretly_empty = def.variants.is_empty()
- && !cx.tcx.features().exhaustive_patterns
- && !pcx.is_top_level;
-
- if is_secretly_empty || is_declared_nonexhaustive {
- vec![NonExhaustive]
- } else if cx.tcx.features().exhaustive_patterns {
- // If `exhaustive_patterns` is enabled, we exclude variants known to be
- // uninhabited.
- def.variants
- .iter()
- .filter(|v| {
- !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
- .contains(cx.tcx, cx.module)
- })
- .map(|v| Variant(v.def_id))
- .collect()
- } else {
- def.variants.iter().map(|v| Variant(v.def_id)).collect()
- }
- }
- ty::Char => {
- vec![
- // The valid Unicode Scalar Value ranges.
- make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
- make_range('\u{E000}' as u128, '\u{10FFFF}' as u128),
- ]
- }
- ty::Int(_) | ty::Uint(_)
- if pcx.ty.is_ptr_sized_integral()
- && !cx.tcx.features().precise_pointer_size_matching =>
- {
- // `usize`/`isize` are not allowed to be matched exhaustively unless the
- // `precise_pointer_size_matching` feature is enabled. So we treat those types like
- // `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
- vec![NonExhaustive]
- }
- &ty::Int(ity) => {
- let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
- let min = 1u128 << (bits - 1);
- let max = min - 1;
- vec![make_range(min, max)]
- }
- &ty::Uint(uty) => {
- let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
- let max = size.truncate(u128::MAX);
- vec![make_range(0, max)]
- }
- // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
- // expose its emptiness. The exception is if the pattern is at the top level, because we
- // want empty matches to be considered exhaustive.
- ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => {
- vec![NonExhaustive]
- }
- ty::Never => vec![],
- _ if cx.is_uninhabited(pcx.ty) => vec![],
- ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single],
- // This type is one for which we cannot list constructors, like `str` or `f64`.
- _ => vec![NonExhaustive],
- }
-}
-
-// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
+/// A constructor that is not present in the matrix rows will only be covered by the rows that have
+/// wildcards. Thus we can group all of those constructors together; we call them "missing
+/// constructors". Splitting a wildcard would therefore list all present constructors individually
+/// (or grouped if they are integers or slices), and then all missing constructors together as a
+/// group.
+///
+/// However we can go further: since any constructor will match the wildcard rows, and having more
+/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors
+/// and only try the missing ones.
+/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty
+/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done
+/// in `to_ctors`: in some cases we only return `Missing`.
#[derive(Debug)]
-pub(super) struct MissingConstructors<'tcx> {
+pub(super) struct SplitWildcard<'tcx> {
+ /// Constructors seen in the matrix.
+ matrix_ctors: Vec<Constructor<'tcx>>,
+ /// All the constructors for this type
all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
- used_ctors: Vec<Constructor<'tcx>>,
}
-impl<'tcx> MissingConstructors<'tcx> {
+impl<'tcx> SplitWildcard<'tcx> {
pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
- let used_ctors: Vec<Constructor<'_>> =
- pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect();
- // Since `all_ctors` never contains wildcards, this won't recurse further.
- let all_ctors =
- all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx, None)).collect();
+ debug!("SplitWildcard::new({:?})", pcx.ty);
+ let cx = pcx.cx;
+ let make_range = |start, end| {
+ IntRange(
+ // `unwrap()` is ok because we know the type is an integer.
+ IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(),
+ )
+ };
+ // This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
+ // arrays and slices we use ranges and variable-length slices when appropriate.
+ //
+ // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that
+ // are statically impossible. E.g., for `Option<!>`, we do not include `Some(_)` in the
+ // returned list of constructors.
+ // Invariant: this is empty if and only if the type is uninhabited (as determined by
+ // `cx.is_uninhabited()`).
+ let all_ctors = match pcx.ty.kind() {
+ ty::Bool => smallvec![make_range(0, 1)],
+ ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
+ let len = len.eval_usize(cx.tcx, cx.param_env);
+ if len != 0 && cx.is_uninhabited(sub_ty) {
+ smallvec![]
+ } else {
+ smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
+ }
+ }
+ // Treat arrays of a constant but unknown length like slices.
+ ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
+ let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
+ smallvec![Slice(Slice::new(None, kind))]
+ }
+ ty::Adt(def, substs) if def.is_enum() => {
+ // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
+ // additional "unknown" constructor.
+ // There is no point in enumerating all possible variants, because the user can't
+ // actually match against them all themselves. So we always return only the fictitious
+ // constructor.
+ // E.g., in an example like:
+ //
+ // ```
+ // let err: io::ErrorKind = ...;
+ // match err {
+ // io::ErrorKind::NotFound => {},
+ // }
+ // ```
+ //
+ // we don't want to show every possible IO error, but instead have only `_` as the
+ // witness.
+ let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
+
+ // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
+ // as though it had an "unknown" constructor to avoid exposing its emptiness. The
+ // exception is if the pattern is at the top level, because we want empty matches to be
+ // considered exhaustive.
+ let is_secretly_empty = def.variants.is_empty()
+ && !cx.tcx.features().exhaustive_patterns
+ && !pcx.is_top_level;
+
+ if is_secretly_empty || is_declared_nonexhaustive {
+ smallvec![NonExhaustive]
+ } else if cx.tcx.features().exhaustive_patterns {
+ // If `exhaustive_patterns` is enabled, we exclude variants known to be
+ // uninhabited.
+ def.variants
+ .iter()
+ .filter(|v| {
+ !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
+ .contains(cx.tcx, cx.module)
+ })
+ .map(|v| Variant(v.def_id))
+ .collect()
+ } else {
+ def.variants.iter().map(|v| Variant(v.def_id)).collect()
+ }
+ }
+ ty::Char => {
+ smallvec![
+ // The valid Unicode Scalar Value ranges.
+ make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
+ make_range('\u{E000}' as u128, '\u{10FFFF}' as u128),
+ ]
+ }
+ ty::Int(_) | ty::Uint(_)
+ if pcx.ty.is_ptr_sized_integral()
+ && !cx.tcx.features().precise_pointer_size_matching =>
+ {
+ // `usize`/`isize` are not allowed to be matched exhaustively unless the
+ // `precise_pointer_size_matching` feature is enabled. So we treat those types like
+ // `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
+ smallvec![NonExhaustive]
+ }
+ &ty::Int(ity) => {
+ let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
+ let min = 1u128 << (bits - 1);
+ let max = min - 1;
+ smallvec![make_range(min, max)]
+ }
+ &ty::Uint(uty) => {
+ let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
+ let max = size.truncate(u128::MAX);
+ smallvec![make_range(0, max)]
+ }
+ // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
+ // expose its emptiness. The exception is if the pattern is at the top level, because we
+ // want empty matches to be considered exhaustive.
+ ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => {
+ smallvec![NonExhaustive]
+ }
+ ty::Never => smallvec![],
+ _ if cx.is_uninhabited(pcx.ty) => smallvec![],
+ ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single],
+ // This type is one for which we cannot list constructors, like `str` or `f64`.
+ _ => smallvec![NonExhaustive],
+ };
+ SplitWildcard { matrix_ctors: Vec::new(), all_ctors }
+ }
- MissingConstructors { all_ctors, used_ctors }
+ /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't
+ /// do what you want.
+ pub(super) fn split<'a>(
+ &mut self,
+ pcx: PatCtxt<'_, '_, 'tcx>,
+ ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
+ ) where
+ 'tcx: 'a,
+ {
+ // Since `all_ctors` never contains wildcards, this won't recurse further.
+ self.all_ctors =
+ self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
+ self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
}
- fn is_empty<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> bool {
- self.iter(pcx).next().is_none()
+ /// Whether there are any value constructors for this type that are not present in the matrix.
+ fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+ self.iter_missing(pcx).next().is_some()
}
- /// Iterate over all_ctors \ used_ctors
- fn iter<'a, 'p>(
+ /// Iterate over the constructors for this type that are not present in the matrix.
+ pub(super) fn iter_missing<'a, 'p>(
&'a self,
pcx: PatCtxt<'a, 'p, 'tcx>,
) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
- self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.used_ctors))
+ self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
}
- /// List the patterns corresponding to the missing constructors. In some cases, instead of
- /// listing all constructors of a given type, we prefer to simply report a wildcard.
- pub(super) fn report_patterns<'p>(
- &self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- ) -> SmallVec<[Pat<'tcx>; 1]> {
- // There are 2 ways we can report a witness here.
- // Commonly, we can report all the "free"
- // constructors as witnesses, e.g., if we have:
- //
- // ```
- // enum Direction { N, S, E, W }
- // let Direction::N = ...;
- // ```
- //
- // we can report 3 witnesses: `S`, `E`, and `W`.
- //
- // However, there is a case where we don't want
- // to do this and instead report a single `_` witness:
- // if the user didn't actually specify a constructor
- // in this arm, e.g., in
- //
- // ```
- // let x: (Direction, Direction, bool) = ...;
- // let (_, _, false) = x;
- // ```
- //
- // we don't want to show all 16 possible witnesses
- // `(<direction-1>, <direction-2>, true)` - we are
- // satisfied with `(_, _, true)`. In this case,
- // `used_ctors` is empty.
- // The exception is: if we are at the top-level, for example in an empty match, we
- // sometimes prefer reporting the list of constructors instead of just `_`.
- let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
- if self.used_ctors.is_empty() && !report_when_all_missing {
- // All constructors are unused. Report only a wildcard
- // rather than each individual constructor.
- smallvec![Pat::wildcard_from_ty(pcx.ty)]
- } else {
- // Construct for each missing constructor a "wild" version of this
- // constructor, that matches everything that can be built with
- // it. For example, if `ctor` is a `Constructor::Variant` for
- // `Option::Some`, we get the pattern `Some(_)`.
- self.iter(pcx)
- .map(|missing_ctor| Fields::wildcards(pcx, &missing_ctor).apply(pcx, missing_ctor))
- .collect()
+ /// Return the set of constructors resulting from splitting the wildcard. As explained at the
+ /// top of the file, if any constructors are missing we can ignore the present ones.
+ fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
+ if self.any_missing(pcx) {
+ // Some constructors are missing, thus we can specialize with the special `Missing`
+ // constructor, which stands for those constructors that are not seen in the matrix,
+ // and matches the same rows as any of them (namely the wildcard rows). See the top of
+ // the file for details.
+ // However, when all constructors are missing we can also specialize with the full
+ // `Wildcard` constructor. The difference will depend on what we want in diagnostics.
+
+ // If some constructors are missing, we typically want to report those constructors,
+ // e.g.:
+ // ```
+ // enum Direction { N, S, E, W }
+ // let Direction::N = ...;
+ // ```
+ // we can report 3 witnesses: `S`, `E`, and `W`.
+ //
+ // However, if the user didn't actually specify a constructor
+ // in this arm, e.g., in
+ // ```
+ // let x: (Direction, Direction, bool) = ...;
+ // let (_, _, false) = x;
+ // ```
+ // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
+ // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
+ // prefer to report just a wildcard `_`.
+ //
+ // The exception is: if we are at the top-level, for example in an empty match, we
+ // sometimes prefer reporting the list of constructors instead of just `_`.
+ let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
+ let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing {
+ Missing
+ } else {
+ Wildcard
+ };
+ return smallvec![ctor];
}
+
+ // All the constructors are present in the matrix, so we just go through them all.
+ self.all_ctors
}
}
/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
-/// `Fields` struct. This struct represents such a potentially-hidden field. When a field is hidden
-/// we still keep its type around.
+/// `Fields` struct. This struct represents such a potentially-hidden field.
#[derive(Debug, Copy, Clone)]
pub(super) enum FilteredField<'p, 'tcx> {
Kept(&'p Pat<'tcx>),
- Hidden(Ty<'tcx>),
+ Hidden,
}
impl<'p, 'tcx> FilteredField<'p, 'tcx> {
fn kept(self) -> Option<&'p Pat<'tcx>> {
match self {
FilteredField::Kept(p) => Some(p),
- FilteredField::Hidden(_) => None,
- }
- }
-
- fn to_pattern(self) -> Pat<'tcx> {
- match self {
- FilteredField::Kept(p) => p.clone(),
- FilteredField::Hidden(ty) => Pat::wildcard_from_ty(ty),
+ FilteredField::Hidden => None,
}
}
}
/// A value can be decomposed into a constructor applied to some fields. This struct represents
/// those fields, generalized to allow patterns in each field. See also `Constructor`.
+/// This is constructed from a constructor using [`Fields::wildcards()`].
///
/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
-/// uninhabited. For that, we filter these fields out of the matrix. This is subtle because we
-/// still need to have those fields back when going to/from a `Pat`. Most of this is handled
-/// automatically in `Fields`, but when constructing or deconstructing `Fields` you need to be
-/// careful. As a rule, when going to/from the matrix, use the filtered field list; when going
-/// to/from `Pat`, use the full field list.
-/// This filtering is uncommon in practice, because uninhabited fields are rarely used, so we avoid
-/// it when possible to preserve performance.
+/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically
+/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used,
+/// so we avoid it when possible to preserve performance.
#[derive(Debug, Clone)]
pub(super) enum Fields<'p, 'tcx> {
/// Lists of patterns that don't contain any filtered fields.
/// have not measured if it really made a difference.
Slice(&'p [Pat<'tcx>]),
Vec(SmallVec<[&'p Pat<'tcx>; 2]>),
- /// Patterns where some of the fields need to be hidden. `kept_count` caches the number of
- /// non-hidden fields.
+ /// Patterns where some of the fields need to be hidden. For all intents and purposes we only
+ /// care about the non-hidden fields. We need to keep the real field index for those fields;
+ /// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient.
+ /// `len` counts the number of non-hidden fields
Filtered {
fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
- kept_count: usize,
+ len: usize,
},
}
impl<'p, 'tcx> Fields<'p, 'tcx> {
- fn empty() -> Self {
- Fields::Slice(&[])
- }
-
- /// Construct a new `Fields` from the given pattern. Must not be used if the pattern is a field
- /// of a struct/tuple/variant.
+ /// Internal use. Use `Fields::wildcards()` instead.
+ /// Must not be used if the pattern is a field of a struct/tuple/variant.
fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
Fields::Slice(std::slice::from_ref(pat))
}
if has_no_hidden_fields {
Fields::wildcards_from_tys(cx, field_tys)
} else {
- let mut kept_count = 0;
+ let mut len = 0;
let fields = variant
.fields
.iter()
// order not to reveal the uninhabitedness of the whole
// variant.
if is_uninhabited && (!is_visible || is_non_exhaustive) {
- FilteredField::Hidden(ty)
+ FilteredField::Hidden
} else {
- kept_count += 1;
+ len += 1;
FilteredField::Kept(wildcard_from_ty(ty))
}
})
.collect();
- Fields::Filtered { fields, kept_count }
+ Fields::Filtered { fields, len }
}
}
}
}
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
},
- Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => {
- Fields::empty()
- }
+ Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing
+ | Wildcard => Fields::Slice(&[]),
};
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
ret
/// `self`: `[false]`
/// returns `Some(false)`
pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> {
- let mut subpatterns = self.all_patterns();
+ let subpatterns_and_indices = self.patterns_and_indices();
+ let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned();
let pat = match ctor {
Single | Variant(_) => match pcx.ty.kind() {
ty::Adt(..) | ty::Tuple(..) => {
- let subpatterns = subpatterns
- .enumerate()
- .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+ // We want the real indices here.
+ let subpatterns = subpatterns_and_indices
+ .iter()
+ .map(|&(field, p)| FieldPat { field, pattern: p.clone() })
.collect();
if let ty::Adt(adt, substs) = pcx.ty.kind() {
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty),
NonExhaustive => PatKind::Wild,
+ Wildcard => return Pat::wildcard_from_ty(pcx.ty),
Opaque => bug!("we should not try to apply an opaque constructor"),
- Wildcard => bug!(
- "trying to apply a wildcard constructor; this should have been done in `apply_constructors`"
+ Missing => bug!(
+ "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`"
),
};
Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
}
- /// Returns the number of patterns from the viewpoint of match-checking, i.e. excluding hidden
- /// fields. This is what we want in most cases in this file, the only exception being
- /// conversion to/from `Pat`.
+ /// Returns the number of patterns. This is the same as the arity of the constructor used to
+ /// construct `self`.
pub(super) fn len(&self) -> usize {
match self {
Fields::Slice(pats) => pats.len(),
Fields::Vec(pats) => pats.len(),
- Fields::Filtered { kept_count, .. } => *kept_count,
+ Fields::Filtered { len, .. } => *len,
}
}
- /// Returns the complete list of patterns, including hidden fields.
- fn all_patterns(self) -> impl Iterator<Item = Pat<'tcx>> {
- let pats: SmallVec<[_; 2]> = match self {
- Fields::Slice(pats) => pats.iter().cloned().collect(),
- Fields::Vec(pats) => pats.into_iter().cloned().collect(),
+ /// Returns the list of patterns along with the corresponding field indices.
+ fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> {
+ match self {
+ Fields::Slice(pats) => {
+ pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
+ }
+ Fields::Vec(pats) => {
+ pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
+ }
Fields::Filtered { fields, .. } => {
- // We don't skip any fields here.
- fields.into_iter().map(|p| p.to_pattern()).collect()
+ // Indices must be relative to the full list of patterns
+ fields
+ .iter()
+ .enumerate()
+ .filter_map(|(i, p)| Some((Field::new(i), p.kept()?)))
+ .collect()
}
- };
- pats.into_iter()
+ }
}
- /// Returns the filtered list of patterns, not including hidden fields.
- pub(super) fn filtered_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
+ /// Returns the list of patterns.
+ pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
match self {
Fields::Slice(pats) => pats.iter().collect(),
Fields::Vec(pats) => pats,
- Fields::Filtered { fields, .. } => {
- // We skip hidden fields here
- fields.into_iter().filter_map(|p| p.kept()).collect()
- }
+ Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(),
}
}
}
/// Overrides some of the fields with the provided patterns. This is used when a pattern
- /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start with a
- /// `Fields` that is just one wildcard per field of the `Foo` struct, and override the entry
- /// corresponding to `field1` with the pattern `Some(_)`. This is also used for slice patterns
- /// for the same reason.
+ /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start
+ /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the
+ /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice
+ /// patterns for the same reason.
fn replace_fields_indexed(
&self,
new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
fields
}
- /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the
- /// matrix. There must be `len()` patterns in `pats`.
+ /// Replaces contained fields with the given list of patterns. There must be `len()` patterns
+ /// in `pats`.
pub(super) fn replace_fields(
&self,
cx: &MatchCheckCtxt<'p, 'tcx>,
let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
match self {
- Fields::Filtered { fields, kept_count } => {
+ Fields::Filtered { fields, len } => {
let mut pats = pats.iter();
let mut fields = fields.clone();
for f in &mut fields {
*p = pats.next().unwrap();
}
}
- Fields::Filtered { fields, kept_count: *kept_count }
+ Fields::Filtered { fields, len: *len }
}
_ => Fields::Slice(pats),
}
//!
//! -----
//!
-//! This file includes the logic for exhaustiveness and usefulness checking for
-//! pattern-matching. Specifically, given a list of patterns for a type, we can
-//! tell whether:
-//! (a) the patterns cover every possible constructor for the type (exhaustiveness)
-//! (b) each pattern is necessary (usefulness)
+//! This file includes the logic for exhaustiveness and reachability checking for pattern-matching.
+//! Specifically, given a list of patterns for a type, we can tell whether:
+//! (a) each pattern is reachable (reachability)
+//! (b) the patterns cover every possible value for the type (exhaustiveness)
//!
-//! The algorithm implemented here is a modified version of the one described in
-//! [this paper](http://moscova.inria.fr/~maranget/papers/warn/index.html).
-//! However, to save future implementors from reading the original paper, we
-//! summarise the algorithm here to hopefully save time and be a little clearer
-//! (without being so rigorous).
+//! The algorithm implemented here is a modified version of the one described in [this
+//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized
+//! it to accommodate the variety of patterns that Rust supports. We thus explain our version here,
+//! without being as rigorous.
//!
-//! # Premise
//!
-//! The core of the algorithm revolves about a "usefulness" check. In particular, we
-//! are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
-//! a matrix). `U(P, p)` represents whether, given an existing list of patterns
-//! `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously-
-//! uncovered values of the type).
+//! # Summary
//!
-//! If we have this predicate, then we can easily compute both exhaustiveness of an
-//! entire set of patterns and the individual usefulness of each one.
-//! (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard
-//! match doesn't increase the number of values we're matching)
-//! (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a
-//! pattern to those that have come before it doesn't increase the number of values
-//! we're matching).
+//! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful*
+//! relative to another pattern `p` of the same type if there is a value that is matched by `q` and
+//! not matched by `p`. This generalizes to many `p`s: `q` is useful w.r.t. a list of patterns
+//! `p_1 .. p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write
+//! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this
+//! file is to compute it efficiently.
//!
-//! # Core concept
+//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it
+//! is useful w.r.t. the patterns above it:
+//! ```rust
+//! match x {
+//! Some(_) => ...,
+//! None => ..., // reachable: `None` is matched by this but not the branch above
+//! Some(0) => ..., // unreachable: all the values this matches are already matched by
+//! // `Some(_)` above
+//! }
+//! ```
+//!
+//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_`
+//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness`
+//! are used to tell the user which values are missing.
+//! ```rust
+//! match x {
+//! Some(0) => ...,
+//! None => ...,
+//! // not exhaustive: `_` is useful because it matches `Some(1)`
+//! }
+//! ```
//!
-//! The idea that powers everything that is done in this file is the following: a value is made
-//! from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)`
-//! (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the
-//! constructor for the number `2`). Fields are just a (possibly empty) list of values.
+//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes
+//! reachability for each match branch and exhaustiveness for the whole match.
//!
-//! Some of the constructors listed above might feel weird: `None` and `2` don't take any
-//! arguments. This is part of what makes constructors so general: we will consider plain values
-//! like numbers and string literals to be constructors that take no arguments, also called "0-ary
-//! constructors"; they are the simplest case of constructors. This allows us to see any value as
-//! made up from a tree of constructors, each having a given number of children. For example:
-//! `(None, Ok(0))` is made from 4 different constructors.
//!
-//! This idea can be extended to patterns: a pattern captures a set of possible values, and we can
-//! describe this set using constructors. For example, `Err(_)` captures all values of the type
-//! `Result<T, E>` that start with the `Err` constructor (for some choice of `T` and `E`). The
-//! wildcard `_` captures all values of the given type starting with any of the constructors for
-//! that type.
+//! # Constructors and fields
//!
-//! We use this to compute whether different patterns might capture a same value. Do the patterns
-//! `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern
-//! captures only values starting with the `Ok` constructor and the second only values starting
-//! with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might,
-//! since they both capture values starting with `Some`. To be certain, we need to dig under the
-//! `Some` constructor and continue asking the question. This is the main idea behind the
-//! exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently
-//! figure out if some new pattern might capture a value that hadn't been captured by previous
-//! patterns.
+//! Note: we will often abbreviate "constructor" as "ctor".
//!
-//! Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum.
-//! Most of the complexity of this file resides in transforming between patterns and
-//! (`Constructor`, `Fields`) pairs, handling all the special cases correctly.
+//! The idea that powers everything that is done in this file is the following: a (matcheable)
+//! value is made from a constructor applied to a number of subvalues. Examples of constructors are
+//! `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor for a struct
+//! `Foo`), and `2` (the constructor for the number `2`). This is natural when we think of
+//! pattern-matching, and this is the basis for what follows.
//!
-//! Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example
-//! a value of type `Rc<u64>` doesn't fit this idea very well, nor do various other things.
-//! However, this idea covers most of the cases that are relevant to exhaustiveness checking.
+//! Some of the ctors listed above might feel weird: `None` and `2` don't take any arguments.
+//! That's ok: those are ctors that take a list of 0 arguments; they are the simplest case of
+//! ctors. We treat `2` as a ctor because `u64` and other number types behave exactly like a huge
+//! `enum`, with one variant for each number. This allows us to see any matcheable value as made up
+//! from a tree of ctors, each having a set number of children. For example: `Foo { bar: None,
+//! baz: Ok(0) }` is made from 4 different ctors, namely `Foo{..}`, `None`, `Ok` and `0`.
//!
+//! This idea can be extended to patterns: they are also made from constructors applied to fields.
+//! A pattern for a given type is allowed to use all the ctors for values of that type (which we
+//! call "value constructors"), but there are also pattern-only ctors. The most important one is
+//! the wildcard (`_`), and the others are integer ranges (`0..=10`), variable-length slices (`[x,
+//! ..]`), and or-patterns (`Ok(0) | Err(_)`). Examples of valid patterns are `42`, `Some(_)`, `Foo
+//! { bar: Some(0) | None, baz: _ }`. Note that a binder in a pattern (e.g. `Some(x)`) matches the
+//! same values as a wildcard (e.g. `Some(_)`), so we treat both as wildcards.
//!
-//! # Algorithm
+//! From this deconstruction we can compute whether a given value matches a given pattern; we
+//! simply look at ctors one at a time. Given a pattern `p` and a value `v`, we want to compute
+//! `matches!(v, p)`. It's mostly straightforward: we compare the head ctors and when they match
+//! we compare their fields recursively. A few representative examples:
//!
-//! Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`,
-//! adding a new pattern `p` will cover previously-uncovered values of the type.
-//! During the course of the algorithm, the rows of the matrix won't just be individual patterns,
-//! but rather partially-deconstructed patterns in the form of a list of fields. The paper
-//! calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
-//! new pattern `p`.
+//! - `matches!(v, _) := true`
+//! - `matches!((v0, v1), (p0, p1)) := matches!(v0, p0) && matches!(v1, p1)`
+//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)`
+//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)`
+//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants)
+//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)`
+//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths)
+//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)`
+//! - `matches!(v, p0 | p1) := matches!(v, p0) || matches!(v, p1)`
//!
-//! For example, say we have the following:
+//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] module.
//!
+//! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type.
+//! For example a value of type `Rc<u64>` can't be deconstructed that way, and `&str` has an
+//! infinitude of constructors. There are also subtleties with visibility of fields and
+//! uninhabitedness and various other things. The constructors idea can be extended to handle most
+//! of these subtleties though; caveats are documented where relevant throughout the code.
+//!
+//! Whether constructors cover each other is computed by [`Constructor::is_covered_by`].
+//!
+//!
+//! # Specialization
+//!
+//! Recall that we wish to compute `usefulness(p_1 .. p_n, q)`: given a list of patterns `p_1 ..
+//! p_n` and a pattern `q`, all of the same type, we want to find a list of values (called
+//! "witnesses") that are matched by `q` and by none of the `p_i`. We obviously don't just
+//! enumerate all possible values. From the discussion above we see that we can proceed
+//! ctor-by-ctor: for each value ctor of the given type, we ask "is there a value that starts with
+//! this constructor and matches `q` and none of the `p_i`?". As we saw above, there's a lot we can
+//! say from knowing only the first constructor of our candidate value.
+//!
+//! Let's take the following example:
//! ```
-//! // x: (Option<bool>, Result<()>)
//! match x {
-//! (Some(true), _) => {}
-//! (None, Err(())) => {}
-//! (None, Err(_)) => {}
+//! Enum::Variant1(_) => {} // `p1`
+//! Enum::Variant2(None, 0) => {} // `p2`
+//! Enum::Variant2(Some(_), 0) => {} // `q`
//! }
//! ```
//!
-//! Here, the matrix `P` starts as:
+//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`.
+//! If `v = Variant2(v0, v1)` however, whether or not it matches `p2` and `q` will depend on `v0`
+//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple
+//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match:
//!
//! ```
-//! [
-//! [(Some(true), _)],
-//! [(None, Err(()))],
-//! [(None, Err(_))],
-//! ]
+//! match x {
+//! (None, 0) => {} // `p2'`
+//! (Some(_), 0) => {} // `q'`
+//! }
//! ```
//!
-//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
-//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
-//! all the values it covers are already covered by row 2.
+//! This motivates a new step in computing usefulness, that we call _specialization_.
+//! Specialization consist of filtering a list of patterns for those that match a constructor, and
+//! then looking into the constructor's fields. This enables usefulness to be computed recursively.
//!
-//! A list of patterns can be thought of as a stack, because we are mainly interested in the top of
-//! the stack at any given point, and we can pop or apply constructors to get new pattern-stacks.
-//! To match the paper, the top of the stack is at the beginning / on the left.
+//! Instead of acting on a single pattern in each row, we will consider a list of patterns for each
+//! row, and we call such a list a _pattern-stack_. The idea is that we will specialize the
+//! leftmost pattern, which amounts to popping the constructor and pushing its fields, which feels
+//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`.
+//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's
+//! happening:
+//! ```
+//! [Enum::Variant1(_)]
+//! [Enum::Variant2(None, 0)]
+//! [Enum::Variant2(Some(_), 0)]
+//! //==>> specialize with `Variant2`
+//! [None, 0]
+//! [Some(_), 0]
+//! //==>> specialize with `Some`
+//! [_, 0]
+//! //==>> specialize with `true` (say the type was `bool`)
+//! [0]
+//! //==>> specialize with `0`
+//! []
+//! ```
//!
-//! There are two important operations on pattern-stacks necessary to understand the algorithm:
+//! The function `specialize(c, p)` takes a value constructor `c` and a pattern `p`, and returns 0
+//! or more pattern-stacks. If `c` does not match the head constructor of `p`, it returns nothing;
+//! otherwise if returns the fields of the constructor. This only returns more than one
+//! pattern-stack if `p` has a pattern-only constructor.
//!
-//! 1. We can pop a given constructor off the top of a stack. This operation is called
-//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
-//! `None`) and `p` a pattern-stack.
-//! If the pattern on top of the stack can cover `c`, this removes the constructor and
-//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
-//! Otherwise the pattern-stack is discarded.
-//! This essentially filters those pattern-stacks whose top covers the constructor `c` and
-//! discards the others.
+//! - Specializing for the wrong constructor returns nothing
//!
-//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
-//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
-//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
-//! nothing back.
+//! `specialize(None, Some(p0)) := []`
//!
-//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
-//! on top of the stack, and we have four cases:
+//! - Specializing for the correct constructor returns a single row with the fields
//!
-//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
-//! push onto the stack the arguments of this constructor, and return the result:
-//! `r_1, .., r_a, p_2, .., p_n`
+//! `specialize(Variant1, Variant1(p0, p1, p2)) := [[p0, p1, p2]]`
//!
-//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠c'`. We discard the current stack and
-//! return nothing.
+//! `specialize(Foo{..}, Foo { bar: p0, baz: p1 }) := [[p0, p1]]`
//!
-//! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
-//! arguments (its arity), and return the resulting stack:
-//! `_, .., _, p_2, .., p_n`
+//! - For or-patterns, we specialize each branch and concatenate the results
//!
-//! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-//! stack:
-//! - `S(c, (r_1, p_2, .., p_n))`
-//! - `S(c, (r_2, p_2, .., p_n))`
+//! `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)`
//!
-//! 2. We can pop a wildcard off the top of the stack. This is called `S(_, p)`, where `p` is
-//! a pattern-stack. Note: the paper calls this `D(p)`.
-//! This is used when we know there are missing constructor cases, but there might be
-//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check
-//! all its *other* components.
+//! - We treat the other pattern constructors as if they were a large or-pattern of all the
+//! possibilities:
//!
-//! It is computed as follows. We look at the pattern `p_1` on top of the stack,
-//! and we have three cases:
-//! 2.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
-//! 2.2. `p_1 = _`. We return the rest of the stack:
-//! p_2, .., p_n
-//! 2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-//! stack.
-//! - `S(_, (r_1, p_2, .., p_n))`
-//! - `S(_, (r_2, p_2, .., p_n))`
+//! `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)`
//!
-//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the
-//! exhaustive integer matching rules, so they're written here for posterity.
+//! `specialize(c, 1..=100) := specialize(c, 1 | ... | 100)`
//!
-//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
-//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
-//! the given constructor, and popping a wildcard keeps those rows that start with a wildcard.
+//! `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)`
//!
+//! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See
+//! the discussion about constructor splitting in [`super::deconstruct_pat`].
//!
-//! The algorithm for computing `U`
-//! -------------------------------
-//! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
-//! That means we're going to check the components from left-to-right, so the algorithm
-//! operates principally on the first component of the matrix and new pattern-stack `p`.
-//! This algorithm is realised in the `is_useful` function.
//!
-//! Base case. (`n = 0`, i.e., an empty tuple pattern)
-//! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`),
-//! then `U(P, p)` is false.
-//! - Otherwise, `P` must be empty, so `U(P, p)` is true.
+//! We then extend this function to work with pattern-stacks as input, by acting on the first
+//! column and keeping the other columns untouched.
//!
-//! Inductive step. (`n > 0`, i.e., whether there's at least one column
-//! [which may then be expanded into further columns later])
-//! We're going to match on the top of the new pattern-stack, `p_1`.
-//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
-//! Then, the usefulness of `p_1` can be reduced to whether it is useful when
-//! we ignore all the patterns in the first column of `P` that involve other constructors.
-//! This is where `S(c, P)` comes in:
-//! `U(P, p) := U(S(c, P), S(c, p))`
+//! Specialization for the whole matrix is done in [`Matrix::specialize_constructor`]. Note that
+//! or-patterns in the first column are expanded before being stored in the matrix. Specialization
+//! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and
+//! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the
+//! [`Fields`] struct.
//!
-//! For example, if `P` is:
//!
-//! ```
-//! [
-//! [Some(true), _],
-//! [None, 0],
-//! ]
-//! ```
+//! # Computing usefulness
//!
-//! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only
-//! matches values that row 2 doesn't. For row 1 however, we need to dig into the
-//! arguments of `Some` to know whether some new value is covered. So we compute
-//! `U([[true, _]], [false, 0])`.
+//! We now have all we need to compute usefulness. The inputs to usefulness are a list of
+//! pattern-stacks `p_1 ... p_n` (one per row), and a new pattern_stack `q`. The paper and this
+//! file calls the list of patstacks a _matrix_. They must all have the same number of columns and
+//! the patterns in a given column must all have the same type. `usefulness` returns a (possibly
+//! empty) list of witnesses of usefulness. These witnesses will also be pattern-stacks.
//!
-//! - If `p_1 == _`, then we look at the list of constructors that appear in the first
-//! component of the rows of `P`:
-//! + If there are some constructors that aren't present, then we might think that the
-//! wildcard `_` is useful, since it covers those constructors that weren't covered
-//! before.
-//! That's almost correct, but only works if there were no wildcards in those first
-//! components. So we need to check that `p` is useful with respect to the rows that
-//! start with a wildcard, if there are any. This is where `S(_, x)` comes in:
-//! `U(P, p) := U(S(_, P), S(_, p))`
+//! - base case: `n_columns == 0`.
+//! Since a pattern-stack functions like a tuple of patterns, an empty one functions like the
+//! unit type. Thus `q` is useful iff there are no rows above it, i.e. if `n == 0`.
//!
-//! For example, if `P` is:
+//! - inductive case: `n_columns > 0`.
+//! We need a way to list the constructors we want to try. We will be more clever in the next
+//! section but for now assume we list all value constructors for the type of the first column.
//!
-//! ```
-//! [
-//! [_, true, _],
-//! [None, false, 1],
-//! ]
-//! ```
+//! - for each such ctor `c`:
+//!
+//! - for each `q'` returned by `specialize(c, q)`:
//!
-//! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we
-//! only had row 2, we'd know that `p` is useful. However row 1 starts with a
-//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
+//! - we compute `usefulness(specialize(c, p_1) ... specialize(c, p_n), q')`
//!
-//! + Otherwise, all possible constructors (for the relevant type) are present. In this
-//! case we must check whether the wildcard pattern covers any unmatched value. For
-//! that, we can think of the `_` pattern as a big OR-pattern that covers all
-//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
-//! example. The wildcard pattern is useful in this case if it is useful when
-//! specialized to one of the possible constructors. So we compute:
-//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
+//! - for each witness found, we revert specialization by pushing the constructor `c` on top.
//!
-//! For example, if `P` is:
+//! - We return the concatenation of all the witnesses found, if any.
//!
+//! Example:
//! ```
-//! [
-//! [Some(true), _],
-//! [None, false],
-//! ]
+//! [Some(true)] // p_1
+//! [None] // p_2
+//! [Some(_)] // q
+//! //==>> try `None`: `specialize(None, q)` returns nothing
+//! //==>> try `Some`: `specialize(Some, q)` returns a single row
+//! [true] // p_1'
+//! [_] // q'
+//! //==>> try `true`: `specialize(true, q')` returns a single row
+//! [] // p_1''
+//! [] // q''
+//! //==>> base case; `n != 0` so `q''` is not useful.
+//! //==>> go back up a step
+//! [true] // p_1'
+//! [_] // q'
+//! //==>> try `false`: `specialize(false, q')` returns a single row
+//! [] // q''
+//! //==>> base case; `n == 0` so `q''` is useful. We return the single witness `[]`
+//! witnesses:
+//! []
+//! //==>> undo the specialization with `false`
+//! witnesses:
+//! [false]
+//! //==>> undo the specialization with `Some`
+//! witnesses:
+//! [Some(false)]
+//! //==>> we have tried all the constructors. The output is the single witness `[Some(false)]`.
//! ```
//!
-//! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first
-//! components of `P`. We will therefore try popping both constructors in turn: we
-//! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]],
-//! [false])` for the `None` constructor. The first case returns true, so we know that
-//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
-//! before.
+//! This computation is done in [`is_useful`]. In practice we don't care about the list of
+//! witnesses when computing reachability; we only need to know whether any exist. We do keep the
+//! witnesses when computing exhaustiveness to report them to the user.
+//!
//!
-//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
-//! `U(P, p) := U(P, (r_1, p_2, .., p_n))
-//! || U(P, (r_2, p_2, .., p_n))`
+//! # Making usefulness tractable: constructor splitting
//!
-//! Modifications to the algorithm
-//! ------------------------------
-//! The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for
-//! example uninhabited types and variable-length slice patterns. These are drawn attention to
-//! throughout the code below. I'll make a quick note here about how exhaustive integer matching is
-//! accounted for, though.
+//! We're missing one last detail: which constructors do we list? Naively listing all value
+//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The
+//! first obvious insight is that we only want to list constructors that are covered by the head
+//! constructor of `q`. If it's a value constructor, we only try that one. If it's a pattern-only
+//! constructor, we use the final clever idea for this algorithm: _constructor splitting_, where we
+//! group together constructors that behave the same.
//!
-//! Exhaustive integer matching
-//! ---------------------------
-//! An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ...
-//! So to support exhaustive integer matching, we can make use of the logic in the paper for
-//! OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because
-//! they are likely gigantic. So we instead treat ranges as constructors of the integers. This means
-//! that we have a constructor *of* constructors (the integers themselves). We then need to work
-//! through all the inductive step rules above, deriving how the ranges would be treated as
-//! OR-patterns, and making sure that they're treated in the same way even when they're ranges.
-//! There are really only four special cases here:
-//! - When we match on a constructor that's actually a range, we have to treat it as if we would
-//! an OR-pattern.
-//! + It turns out that we can simply extend the case for single-value patterns in
-//! `specialize` to either be *equal* to a value constructor, or *contained within* a range
-//! constructor.
-//! + When the pattern itself is a range, you just want to tell whether any of the values in
-//! the pattern range coincide with values in the constructor range, which is precisely
-//! intersection.
-//! Since when encountering a range pattern for a value constructor, we also use inclusion, it
-//! means that whenever the constructor is a value/range and the pattern is also a value/range,
-//! we can simply use intersection to test usefulness.
-//! - When we're testing for usefulness of a pattern and the pattern's first component is a
-//! wildcard.
-//! + If all the constructors appear in the matrix, we have a slight complication. By default,
-//! the behaviour (i.e., a disjunction over specialised matrices for each constructor) is
-//! invalid, because we want a disjunction over every *integer* in each range, not just a
-//! disjunction over every range. This is a bit more tricky to deal with: essentially we need
-//! to form equivalence classes of subranges of the constructor range for which the behaviour
-//! of the matrix `P` and new pattern `p` are the same. This is described in more
-//! detail in `Constructor::split`.
-//! + If some constructors are missing from the matrix, it turns out we don't need to do
-//! anything special (because we know none of the integers are actually wildcards: i.e., we
-//! can't span wildcards using ranges).
+//! The details are not necessary to understand this file, so we explain them in
+//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
use self::Usefulness::*;
use self::WitnessPreference::*;
-use super::deconstruct_pat::{Constructor, Fields, MissingConstructors};
+use super::deconstruct_pat::{Constructor, Fields, SplitWildcard};
use super::{Pat, PatKind};
use super::{PatternFoldable, PatternFolder};
#[derive(Copy, Clone)]
pub(super) struct PatCtxt<'a, 'p, 'tcx> {
pub(super) cx: &'a MatchCheckCtxt<'p, 'tcx>,
- /// Current state of the matrix.
- pub(super) matrix: &'a Matrix<'p, 'tcx>,
/// Type of the current column under investigation.
pub(super) ty: Ty<'tcx>,
/// Span of the current pattern under investigation.
// We pop the head pattern and push the new fields extracted from the arguments of
// `self.head()`.
let mut new_fields =
- ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).filtered_patterns();
+ ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns();
new_fields.extend_from_slice(&self.pats[1..]);
PatStack::from_vec(new_fields)
}
pub(super) fn head_ctors<'a>(
&'a self,
cx: &'a MatchCheckCtxt<'p, 'tcx>,
- ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
+ ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> + Clone {
self.patterns.iter().map(move |r| r.head_ctor(cx))
}
fn apply_constructor<'p>(
self,
pcx: PatCtxt<'_, 'p, 'tcx>,
+ matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
ctor: &Constructor<'tcx>,
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
) -> Self {
match self {
UsefulWithWitness(witnesses) => {
- let new_witnesses = if ctor.is_wildcard() {
- let missing_ctors = MissingConstructors::new(pcx);
- let new_patterns = missing_ctors.report_patterns(pcx);
+ let new_witnesses = if matches!(ctor, Constructor::Missing) {
+ let mut split_wildcard = SplitWildcard::new(pcx);
+ split_wildcard.split(pcx, matrix.head_ctors(pcx.cx));
+ // Construct for each missing constructor a "wild" version of this
+ // constructor, that matches everything that can be built with
+ // it. For example, if `ctor` is a `Constructor::Variant` for
+ // `Option::Some`, we get the pattern `Some(_)`.
+ let new_patterns: Vec<_> = split_wildcard
+ .iter_missing(pcx)
+ .map(|missing_ctor| {
+ Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor)
+ })
+ .collect();
witnesses
.into_iter()
.flat_map(|witness| {
/// We'll perform the following steps:
/// 1. Start with an empty witness
/// `Witness(vec![])`
-/// 2. Push a witness `Some(_)` against the `None`
-/// `Witness(vec![Some(_)])`
-/// 3. Push a witness `true` against the `false`
-/// `Witness(vec![Some(_), true])`
+/// 2. Push a witness `true` against the `false`
+/// `Witness(vec![true])`
+/// 3. Push a witness `Some(_)` against the `None`
+/// `Witness(vec![true, Some(_)])`
/// 4. Apply the `Pair` constructor to the witnesses
/// `Witness(vec![Pair(Some(_), true)])`
///
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty);
- let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level };
+ let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
});
Usefulness::merge(usefulnesses)
} else {
+ let v_ctor = v.head_ctor(cx);
+ if let Constructor::IntRange(ctor_range) = &v_ctor {
+ // Lint on likely incorrect range patterns (#63987)
+ ctor_range.lint_overlapping_range_endpoints(
+ pcx,
+ matrix.head_ctors_and_spans(cx),
+ matrix.column_count().unwrap_or(0),
+ hir_id,
+ )
+ }
// We split the head constructor of `v`.
- let ctors = v.head_ctor(cx).split(pcx, Some(hir_id));
+ let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx));
// For each constructor, we compute whether there's a value that starts with it that would
// witness the usefulness of `v`.
- let usefulnesses = ctors.into_iter().map(|ctor| {
+ let start_matrix = &matrix;
+ let usefulnesses = split_ctors.into_iter().map(|ctor| {
// We cache the result of `Fields::wildcards` because it is used a lot.
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
- let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
+ let spec_matrix =
+ start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
let v = v.pop_head_constructor(&ctor_wild_subpatterns);
let usefulness =
- is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
- usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
+ is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns)
});
Usefulness::merge(usefulnesses)
};
/// The arm of a match expression.
#[derive(Clone, Copy)]
crate struct MatchArm<'p, 'tcx> {
- /// The pattern must have been lowered through `MatchVisitor::lower_pattern`.
+ /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
crate pat: &'p super::Pat<'tcx>,
crate hir_id: HirId,
crate has_guard: bool,
/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
/// of its arms are reachable.
///
-/// Note: the input patterns must have been lowered through `MatchVisitor::lower_pattern`.
+/// Note: the input patterns must have been lowered through
+/// `check_match::MatchVisitor::lower_pattern`.
crate fn compute_match_usefulness<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
arms: &[MatchArm<'p, 'tcx>],
use rustc_ast as ast;
use rustc_ast::attr::HasAttrs;
-use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{self, LazyTokenStream, TokenStream, TokenTree};
+use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens, LazyTokenStream, TokenStream};
use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diagnostic, FatalError, Level, PResult};
use rustc_session::parse::ParseSess;
-use rustc_span::{symbol::kw, FileName, SourceFile, Span, DUMMY_SP};
+use rustc_span::{FileName, SourceFile, Span};
-use smallvec::SmallVec;
-use std::cell::RefCell;
-use std::mem;
use std::path::Path;
use std::str;
-use tracing::{debug, info};
+use tracing::debug;
pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
// NOTE(Centril): The following probably shouldn't be here but it acknowledges the
// fact that architecturally, we are using parsing (read on below to understand why).
-pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> TokenStream {
+pub fn nt_to_tokenstream(
+ nt: &Nonterminal,
+ sess: &ParseSess,
+ span: Span,
+ synthesize_tokens: CanSynthesizeMissingTokens,
+) -> TokenStream {
// A `Nonterminal` is often a parsed AST item. At this point we now
// need to convert the parsed AST to an actual token stream, e.g.
// un-parse it basically.
|tokens: Option<&LazyTokenStream>| tokens.as_ref().map(|t| t.create_token_stream());
let tokens = match *nt {
- Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()),
+ Nonterminal::NtItem(ref item) => {
+ prepend_attrs(sess, &item.attrs, nt, span, item.tokens.as_ref())
+ }
Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()),
- Nonterminal::NtStmt(ref stmt) => prepend_attrs(stmt.attrs(), stmt.tokens()),
+ Nonterminal::NtStmt(ref stmt) => prepend_attrs(sess, stmt.attrs(), nt, span, stmt.tokens()),
Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.as_ref()),
Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.as_ref()),
Nonterminal::NtIdent(ident, is_raw) => {
if expr.tokens.is_none() {
debug!("missing tokens for expr {:?}", expr);
}
- prepend_attrs(&expr.attrs, expr.tokens.as_ref())
+ prepend_attrs(sess, &expr.attrs, nt, span, expr.tokens.as_ref())
}
};
- // Caches the stringification of 'good' `TokenStreams` which passed
- // `tokenstream_probably_equal_for_proc_macro`. This allows us to avoid
- // repeatedly stringifying and comparing the same `TokenStream` for deeply
- // nested nonterminals.
- //
- // We cache by the strinification instead of the `TokenStream` to avoid
- // needing to implement `Hash` for `TokenStream`. Note that it's possible to
- // have two distinct `TokenStream`s that stringify to the same result
- // (e.g. if they differ only in hygiene information). However, any
- // information lost during the stringification process is also intentionally
- // ignored by `tokenstream_probably_equal_for_proc_macro`, so it's fine
- // that a single cache entry may 'map' to multiple distinct `TokenStream`s.
- //
- // This is a temporary hack to prevent compilation blowup on certain inputs.
- // The entire pretty-print/retokenize process will be removed soon.
- thread_local! {
- static GOOD_TOKEN_CACHE: RefCell<FxHashSet<String>> = Default::default();
- }
-
- // FIXME(#43081): Avoid this pretty-print + reparse hack
- // Pretty-print the AST struct without inserting any parenthesis
- // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`).
- // The resulting stream may have incorrect precedence, but it's only
- // ever used for a comparison against the capture tokenstream.
- let source = pprust::nonterminal_to_string_no_extra_parens(nt);
- let filename = FileName::macro_expansion_source_code(&source);
- let reparsed_tokens = parse_stream_from_source_str(filename, source.clone(), sess, Some(span));
-
- // During early phases of the compiler the AST could get modified
- // directly (e.g., attributes added or removed) and the internal cache
- // of tokens my not be invalidated or updated. Consequently if the
- // "lossless" token stream disagrees with our actual stringification
- // (which has historically been much more battle-tested) then we go
- // with the lossy stream anyway (losing span information).
- //
- // Note that the comparison isn't `==` here to avoid comparing spans,
- // but it *also* is a "probable" equality which is a pretty weird
- // definition. We mostly want to catch actual changes to the AST
- // like a `#[cfg]` being processed or some weird `macro_rules!`
- // expansion.
- //
- // What we *don't* want to catch is the fact that a user-defined
- // literal like `0xf` is stringified as `15`, causing the cached token
- // stream to not be literal `==` token-wise (ignoring spans) to the
- // token stream we got from stringification.
- //
- // Instead the "probably equal" check here is "does each token
- // recursively have the same discriminant?" We basically don't look at
- // the token values here and assume that such fine grained token stream
- // modifications, including adding/removing typically non-semantic
- // tokens such as extra braces and commas, don't happen.
if let Some(tokens) = tokens {
- if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source)) {
- return tokens;
- }
-
- // Compare with a non-relaxed delim match to start.
- if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) {
- GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
- return tokens;
- }
-
- // The check failed. This time, we pretty-print the AST struct with parenthesis
- // inserted to preserve precedence. This may cause `None`-delimiters in the captured
- // token stream to match up with inserted parenthesis in the reparsed stream.
- let source_with_parens = pprust::nonterminal_to_string(nt);
- let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens);
-
- if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source_with_parens)) {
- return tokens;
- }
-
- let reparsed_tokens_with_parens = parse_stream_from_source_str(
- filename_with_parens,
- source_with_parens,
- sess,
- Some(span),
- );
-
- // Compare with a relaxed delim match - we want inserted parenthesis in the
- // reparsed stream to match `None`-delimiters in the original stream.
- if tokenstream_probably_equal_for_proc_macro(
- &tokens,
- &reparsed_tokens_with_parens,
- sess,
- true,
- ) {
- GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
- return tokens;
- }
-
- info!(
- "cached tokens found, but they're not \"probably equal\", \
- going with stringified version"
- );
- info!("cached tokens: {}", pprust::tts_to_string(&tokens));
- info!("reparsed tokens: {}", pprust::tts_to_string(&reparsed_tokens_with_parens));
-
- info!("cached tokens debug: {:?}", tokens);
- info!("reparsed tokens debug: {:?}", reparsed_tokens_with_parens);
- }
- reparsed_tokens
-}
-
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-//
-// This is otherwise the same as `eq_unspanned`, only recursing with a
-// different method.
-pub fn tokenstream_probably_equal_for_proc_macro(
- tokens: &TokenStream,
- reparsed_tokens: &TokenStream,
- sess: &ParseSess,
- relaxed_delim_match: bool,
-) -> bool {
- // When checking for `probably_eq`, we ignore certain tokens that aren't
- // preserved in the AST. Because they are not preserved, the pretty
- // printer arbitrarily adds or removes them when printing as token
- // streams, making a comparison between a token stream generated from an
- // AST and a token stream which was parsed into an AST more reliable.
- fn semantic_tree(tree: &TokenTree) -> bool {
- if let TokenTree::Token(token) = tree {
- if let
- // The pretty printer tends to add trailing commas to
- // everything, and in particular, after struct fields.
- | token::Comma
- // The pretty printer collapses many semicolons into one.
- | token::Semi
- // We don't preserve leading `|` tokens in patterns, so
- // we ignore them entirely
- | token::BinOp(token::BinOpToken::Or)
- // We don't preserve trailing '+' tokens in trait bounds,
- // so we ignore them entirely
- | token::BinOp(token::BinOpToken::Plus)
- // The pretty printer can turn `$crate` into `::crate_name`
- | token::ModSep = token.kind {
- return false;
- }
- }
- true
- }
-
- // When comparing two `TokenStream`s, we ignore the `IsJoint` information.
- //
- // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will
- // use `Token.glue` on adjacent tokens with the proper `IsJoint`.
- // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`)
- // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent
- // when determining if two `TokenStream`s are 'probably equal'.
- //
- // Therefore, we use `break_two_token_op` to convert all tokens
- // to the 'unglued' form (if it exists). This ensures that two
- // `TokenStream`s which differ only in how their tokens are glued
- // will be considered 'probably equal', which allows us to keep spans.
- //
- // This is important when the original `TokenStream` contained
- // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces
- // will be omitted when we pretty-print, which can cause the original
- // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`,
- // leading to some tokens being 'glued' together in one stream but not
- // the other. See #68489 for more details.
- fn break_tokens(tree: TokenTree) -> impl Iterator<Item = TokenTree> {
- // In almost all cases, we should have either zero or one levels
- // of 'unglueing'. However, in some unusual cases, we may need
- // to iterate breaking tokens mutliple times. For example:
- // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]'
- let mut token_trees: SmallVec<[_; 2]>;
- if let TokenTree::Token(token) = tree {
- let mut out = SmallVec::<[_; 2]>::new();
- out.push(token);
- // Iterate to fixpoint:
- // * We start off with 'out' containing our initial token, and `temp` empty
- // * If we are able to break any tokens in `out`, then `out` will have
- // at least one more element than 'temp', so we will try to break tokens
- // again.
- // * If we cannot break any tokens in 'out', we are done
- loop {
- let mut temp = SmallVec::<[_; 2]>::new();
- let mut changed = false;
-
- for token in out.into_iter() {
- if let Some((first, second)) = token.kind.break_two_token_op() {
- temp.push(Token::new(first, DUMMY_SP));
- temp.push(Token::new(second, DUMMY_SP));
- changed = true;
- } else {
- temp.push(token);
- }
- }
- out = temp;
- if !changed {
- break;
- }
- }
- token_trees = out.into_iter().map(TokenTree::Token).collect();
- } else {
- token_trees = SmallVec::new();
- token_trees.push(tree);
- }
- token_trees.into_iter()
- }
-
- fn expand_token(tree: TokenTree, sess: &ParseSess) -> impl Iterator<Item = TokenTree> {
- // When checking tokenstreams for 'probable equality', we are comparing
- // a captured (from parsing) `TokenStream` to a reparsed tokenstream.
- // The reparsed Tokenstream will never have `None`-delimited groups,
- // since they are only ever inserted as a result of macro expansion.
- // Therefore, inserting a `None`-delimtied group here (when we
- // convert a nested `Nonterminal` to a tokenstream) would cause
- // a mismatch with the reparsed tokenstream.
- //
- // Note that we currently do not handle the case where the
- // reparsed stream has a `Parenthesis`-delimited group
- // inserted. This will cause a spurious mismatch:
- // issue #75734 tracks resolving this.
-
- let expanded: SmallVec<[_; 1]> =
- if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree {
- nt_to_tokenstream(nt, sess, *span)
- .into_trees()
- .flat_map(|t| expand_token(t, sess))
- .collect()
- } else {
- // Filter before and after breaking tokens,
- // since we may want to ignore both glued and unglued tokens.
- std::iter::once(tree)
- .filter(semantic_tree)
- .flat_map(break_tokens)
- .filter(semantic_tree)
- .collect()
- };
- expanded.into_iter()
- }
-
- // Break tokens after we expand any nonterminals, so that we break tokens
- // that are produced as a result of nonterminal expansion.
- let tokens = tokens.trees().flat_map(|t| expand_token(t, sess));
- let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess));
-
- tokens.eq_by(reparsed_tokens, |t, rt| {
- tokentree_probably_equal_for_proc_macro(&t, &rt, sess, relaxed_delim_match)
- })
-}
-
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-//
-// This is otherwise the same as `eq_unspanned`, only recursing with a
-// different method.
-pub fn tokentree_probably_equal_for_proc_macro(
- token: &TokenTree,
- reparsed_token: &TokenTree,
- sess: &ParseSess,
- relaxed_delim_match: bool,
-) -> bool {
- match (token, reparsed_token) {
- (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => {
- token_probably_equal_for_proc_macro(token, reparsed_token)
- }
- (
- TokenTree::Delimited(_, delim, tokens),
- TokenTree::Delimited(_, reparsed_delim, reparsed_tokens),
- ) if delim == reparsed_delim => tokenstream_probably_equal_for_proc_macro(
- tokens,
- reparsed_tokens,
- sess,
- relaxed_delim_match,
- ),
- (TokenTree::Delimited(_, DelimToken::NoDelim, tokens), reparsed_token) => {
- if relaxed_delim_match {
- if let TokenTree::Delimited(_, DelimToken::Paren, reparsed_tokens) = reparsed_token
- {
- if tokenstream_probably_equal_for_proc_macro(
- tokens,
- reparsed_tokens,
- sess,
- relaxed_delim_match,
- ) {
- return true;
- }
- }
- }
- tokens.len() == 1
- && tokentree_probably_equal_for_proc_macro(
- &tokens.trees().next().unwrap(),
- reparsed_token,
- sess,
- relaxed_delim_match,
- )
- }
- _ => false,
+ return tokens;
+ } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) {
+ return fake_token_stream(sess, nt, span);
+ } else {
+ let pretty = rustc_ast_pretty::pprust::nonterminal_to_string_no_extra_parens(&nt);
+ panic!("Missing tokens at {:?} for nt {:?}", span, pretty);
}
}
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool {
- if mem::discriminant(&first.kind) != mem::discriminant(&other.kind) {
- return false;
- }
- use rustc_ast::token::TokenKind::*;
- match (&first.kind, &other.kind) {
- (&Eq, &Eq)
- | (&Lt, &Lt)
- | (&Le, &Le)
- | (&EqEq, &EqEq)
- | (&Ne, &Ne)
- | (&Ge, &Ge)
- | (&Gt, &Gt)
- | (&AndAnd, &AndAnd)
- | (&OrOr, &OrOr)
- | (&Not, &Not)
- | (&Tilde, &Tilde)
- | (&At, &At)
- | (&Dot, &Dot)
- | (&DotDot, &DotDot)
- | (&DotDotDot, &DotDotDot)
- | (&DotDotEq, &DotDotEq)
- | (&Comma, &Comma)
- | (&Semi, &Semi)
- | (&Colon, &Colon)
- | (&ModSep, &ModSep)
- | (&RArrow, &RArrow)
- | (&LArrow, &LArrow)
- | (&FatArrow, &FatArrow)
- | (&Pound, &Pound)
- | (&Dollar, &Dollar)
- | (&Question, &Question)
- | (&Eof, &Eof) => true,
-
- (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b,
-
- (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b,
-
- (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3,
-
- (&Literal(a), &Literal(b)) => a == b,
-
- (&Lifetime(a), &Lifetime(b)) => a == b,
- (&Ident(a, b), &Ident(c, d)) => {
- b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
- }
-
- (&Interpolated(..), &Interpolated(..)) => panic!("Unexpanded Interpolated!"),
-
- _ => panic!("forgot to add a token?"),
- }
+pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal, span: Span) -> TokenStream {
+ let source = pprust::nonterminal_to_string(nt);
+ let filename = FileName::macro_expansion_source_code(&source);
+ parse_stream_from_source_str(filename, source, sess, Some(span))
}
fn prepend_attrs(
+ sess: &ParseSess,
attrs: &[ast::Attribute],
+ nt: &Nonterminal,
+ span: Span,
tokens: Option<&tokenstream::LazyTokenStream>,
) -> Option<tokenstream::TokenStream> {
- let tokens = tokens?.create_token_stream();
if attrs.is_empty() {
- return Some(tokens);
+ return Some(tokens?.create_token_stream());
}
let mut builder = tokenstream::TokenStreamBuilder::new();
for attr in attrs {
// FIXME: Correctly handle tokens for inner attributes.
// For now, we fall back to reparsing the original AST node
if attr.style == ast::AttrStyle::Inner {
- return None;
+ return Some(fake_token_stream(sess, nt, span));
}
builder.push(attr.tokens());
}
- builder.push(tokens);
+ builder.push(tokens?.create_token_stream());
Some(builder.build())
}
*self = snapshot;
Err(err)
}
+
+ /// Get the diagnostics for the cases where `move async` is found.
+ ///
+ /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword
+ pub(super) fn incorrect_move_async_order_found(
+ &self,
+ move_async_span: Span,
+ ) -> DiagnosticBuilder<'a> {
+ let mut err =
+ self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect");
+ err.span_suggestion_verbose(
+ move_async_span,
+ "try switching the order",
+ "async move".to_owned(),
+ Applicability::MaybeIncorrect,
+ );
+ err
+ }
}
self.sess.gated_spans.gate(sym::async_closure, span);
}
- let capture_clause = self.parse_capture_clause();
+ let capture_clause = self.parse_capture_clause()?;
let decl = self.parse_fn_block_decl()?;
let decl_hi = self.prev_token.span;
let body = match decl.output {
}
/// Parses an optional `move` prefix to a closure-like construct.
- fn parse_capture_clause(&mut self) -> CaptureBy {
- if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref }
+ fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
+ if self.eat_keyword(kw::Move) {
+ // Check for `move async` and recover
+ if self.check_keyword(kw::Async) {
+ let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
+ Err(self.incorrect_move_async_order_found(move_async_span))
+ } else {
+ Ok(CaptureBy::Value)
+ }
+ } else {
+ Ok(CaptureBy::Ref)
+ }
}
/// Parses the `|arg, arg|` header of a closure.
fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.expect_keyword(kw::Async)?;
- let capture_clause = self.parse_capture_clause();
+ let capture_clause = self.parse_capture_clause()?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body);
self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
};
use rustc_errors::PResult;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::kw;
impl<'a> Parser<'a> {
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
- self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span));
-
Ok(GenericParam {
ident,
id: ast::DUMMY_NODE_ID,
let polarity = self.parse_polarity();
// Parse both types and traits as a type, then reinterpret if necessary.
- let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span));
+ let err_path = |span| ast::Path::from_ident(Ident::new(kw::Empty, span));
let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
{
let span = self.prev_token.span.between(self.token.span);
// Skip every token until next possible arg or end.
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
// Create a placeholder argument for proper arg count (issue #34264).
- Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_token.span))))
+ Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span))))
});
// ...now that we've parsed the first argument, `self` is no longer allowed.
first_param = false;
}
match ty {
Ok(ty) => {
- let ident = Ident::new(kw::Invalid, self.prev_token.span);
+ let ident = Ident::new(kw::Empty, self.prev_token.span);
let bm = BindingMode::ByValue(Mutability::Not);
let pat = self.mk_pat_ident(ty.span, bm, ident);
(pat, ty)
Ok(t) => {
// Parsed successfully, therefore most probably the code only
// misses a separator.
- let mut exp_span = self.sess.source_map().next_point(sp);
- if self.sess.source_map().is_multiline(exp_span) {
- exp_span = sp;
- }
expect_err
.span_suggestion_short(
- exp_span,
+ sp,
&format!("missing `{}`", token_str),
token_str,
Applicability::MaybeIncorrect,
pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
match &expr.kind {
ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
- ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
- ast::ExprKind::Lit(_) => true,
- _ => false,
- },
+ ast::ExprKind::Unary(ast::UnOp::Neg, expr) => {
+ matches!(expr.kind, ast::ExprKind::Lit(_))
+ }
// We can only resolve single-segment paths at the moment, because multi-segment paths
// require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
ast::ExprKind::Path(None, path)
// function, then we should explore its block to check for codes that
// may need to be marked as live.
fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
- match tcx.hir().find(hir_id) {
+ matches!(
+ tcx.hir().find(hir_id),
Some(
Node::Item(..)
- | Node::ImplItem(..)
- | Node::ForeignItem(..)
- | Node::TraitItem(..)
- | Node::Variant(..)
- | Node::AnonConst(..)
- | Node::Pat(..),
- ) => true,
- _ => false,
- }
+ | Node::ImplItem(..)
+ | Node::ForeignItem(..)
+ | Node::TraitItem(..)
+ | Node::Variant(..)
+ | Node::AnonConst(..)
+ | Node::Pat(..),
+ )
+ )
}
struct MarkSymbolVisitor<'tcx> {
impl DeadVisitor<'tcx> {
fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool {
- let should_warn = match item.kind {
+ let should_warn = matches!(
+ item.kind,
hir::ItemKind::Static(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Enum(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Union(..) => true,
- _ => false,
- };
+ | hir::ItemKind::Const(..)
+ | hir::ItemKind::Fn(..)
+ | hir::ItemKind::TyAlias(..)
+ | hir::ItemKind::Enum(..)
+ | hir::ItemKind::Struct(..)
+ | hir::ItemKind::Union(..)
+ );
should_warn && !self.symbol_is_live(item.hir_id)
}
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
- let is_shorthand = match param.pat.kind {
- rustc_hir::PatKind::Struct(..) => true,
- _ => false,
- };
+ let is_shorthand = matches!(param.pat.kind, rustc_hir::PatKind::Struct(..));
param.pat.each_binding(|_bm, hir_id, _x, ident| {
let var = if is_shorthand {
Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true })
fn should_warn(&self, var: Variable) -> Option<String> {
let name = self.ir.variable_name(var);
- if name == kw::Invalid {
+ if name == kw::Empty {
return None;
}
let name: &str = &name.as_str();
let macro_module_def_id =
ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id())
.unwrap();
- // FIXME(#71104) Should really be using just `as_local_hir_id` but
- // some `DefId` do not seem to have a corresponding HirId.
let hir_id = macro_module_def_id
.as_local()
- .and_then(|def_id| self.tcx.hir().opt_local_def_id_to_hir_id(def_id));
+ .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
let mut module_id = match hir_id {
Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id,
// `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).
in_update_syntax: bool,
) {
// definition of the field
- let ident = Ident::new(kw::Invalid, use_ctxt);
+ let ident = Ident::new(kw::Empty, use_ctxt);
let current_hir = self.current_item.unwrap();
let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, current_hir).1;
if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
// * When a `DepNode::construct` is called, `arg.to_fingerprint()`
// is responsible for calling `OnDiskCache::store_foreign_def_id_hash`
// if needed
- // * When a `DepNode` is loaded from the `PreviousDepGraph`,
- // then `PreviousDepGraph::index_to_node` is responsible for calling
- // `tcx.register_reused_dep_path_hash`
+ // * When we serialize the on-disk cache, `OnDiskCache::serialize` is
+ // responsible for calling `DepGraph::register_reused_dep_nodes`.
//
// FIXME: Enforce this by preventing manual construction of `DefNode`
// (e.g. add a `_priv: ()` field)
use rustc_data_structures::profiling::QueryInvocationId;
use rustc_data_structures::sharded::{self, Sharded};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
+use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, LockGuard, Lrc, Ordering};
use rustc_data_structures::unlikely;
use rustc_errors::Diagnostic;
use rustc_index::vec::{Idx, IndexVec};
use std::hash::Hash;
use std::marker::PhantomData;
use std::mem;
+use std::ops::Range;
use std::sync::atomic::Ordering::Relaxed;
use super::debug::EdgeFilter;
/// The new encoding of the dependency graph, optimized for red/green
/// tracking. The `current` field is the dependency graph of only the
/// current compilation session: We don't merge the previous dep-graph into
- /// current one anymore.
+ /// current one anymore, but we do reference shared data to save space.
current: CurrentDepGraph<K>,
/// The dep-graph from the previous compilation session. It contains all
}
pub fn query(&self) -> DepGraphQuery<K> {
- let data = self.data.as_ref().unwrap().current.data.lock();
- let nodes: Vec<_> = data.iter().map(|n| n.node).collect();
- let mut edges = Vec::new();
- for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) {
- for &edge_target in edge_targets.iter() {
- let to = data[edge_target].node;
- edges.push((from, to));
+ let data = self.data.as_ref().unwrap();
+ let previous = &data.previous;
+
+ // Note locking order: `prev_index_to_index`, then `data`.
+ let prev_index_to_index = data.current.prev_index_to_index.lock();
+ let data = data.current.data.lock();
+ let node_count = data.hybrid_indices.len();
+ let edge_count = self.edge_count(&data);
+
+ let mut nodes = Vec::with_capacity(node_count);
+ let mut edge_list_indices = Vec::with_capacity(node_count);
+ let mut edge_list_data = Vec::with_capacity(edge_count);
+
+ // See `serialize` for notes on the approach used here.
+
+ edge_list_data.extend(data.unshared_edges.iter().map(|i| i.index()));
+
+ for &hybrid_index in data.hybrid_indices.iter() {
+ match hybrid_index.into() {
+ HybridIndex::New(new_index) => {
+ nodes.push(data.new.nodes[new_index]);
+ let edges = &data.new.edges[new_index];
+ edge_list_indices.push((edges.start.index(), edges.end.index()));
+ }
+ HybridIndex::Red(red_index) => {
+ nodes.push(previous.index_to_node(data.red.node_indices[red_index]));
+ let edges = &data.red.edges[red_index];
+ edge_list_indices.push((edges.start.index(), edges.end.index()));
+ }
+ HybridIndex::LightGreen(lg_index) => {
+ nodes.push(previous.index_to_node(data.light_green.node_indices[lg_index]));
+ let edges = &data.light_green.edges[lg_index];
+ edge_list_indices.push((edges.start.index(), edges.end.index()));
+ }
+ HybridIndex::DarkGreen(prev_index) => {
+ nodes.push(previous.index_to_node(prev_index));
+
+ let edges_iter = previous
+ .edge_targets_from(prev_index)
+ .iter()
+ .map(|&dst| prev_index_to_index[dst].unwrap().index());
+
+ let start = edge_list_data.len();
+ edge_list_data.extend(edges_iter);
+ let end = edge_list_data.len();
+ edge_list_indices.push((start, end));
+ }
}
}
- DepGraphQuery::new(&nodes[..], &edges[..])
+ debug_assert_eq!(nodes.len(), node_count);
+ debug_assert_eq!(edge_list_indices.len(), node_count);
+ debug_assert_eq!(edge_list_data.len(), edge_count);
+
+ DepGraphQuery::new(&nodes[..], &edge_list_indices[..], &edge_list_data[..])
}
pub fn assert_ignored(&self) {
key,
cx,
arg,
- false,
task,
|_key| {
Some(TaskDeps {
phantom_data: PhantomData,
})
},
- |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint),
hash_result,
)
}
key: DepNode<K>,
cx: Ctxt,
arg: A,
- no_tcx: bool,
task: fn(Ctxt, A) -> R,
create_task: fn(DepNode<K>) -> Option<TaskDeps<K>>,
- finish_task_and_alloc_depnode: fn(
- &CurrentDepGraph<K>,
- DepNode<K>,
- Fingerprint,
- Option<TaskDeps<K>>,
- ) -> DepNodeIndex,
hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
) -> (R, DepNodeIndex) {
if let Some(ref data) = self.data {
let task_deps = create_task(key).map(Lock::new);
+ let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
+ let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
- // In incremental mode, hash the result of the task. We don't
- // do anything with the hash yet, but we are computing it
- // anyway so that
- // - we make sure that the infrastructure works and
- // - we can get an idea of the runtime cost.
let mut hcx = cx.create_stable_hashing_context();
-
- let result = if no_tcx {
- task(cx, arg)
- } else {
- K::with_deps(task_deps.as_ref(), || task(cx, arg))
- };
-
let current_fingerprint = hash_result(&mut hcx, &result);
- let dep_node_index = finish_task_and_alloc_depnode(
- &data.current,
- key,
- current_fingerprint.unwrap_or(Fingerprint::ZERO),
- task_deps.map(|lock| lock.into_inner()),
- );
-
let print_status = cfg!(debug_assertions) && cx.debug_dep_tasks();
- // Determine the color of the new DepNode.
- if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
- let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);
-
- let color = if let Some(current_fingerprint) = current_fingerprint {
- if current_fingerprint == prev_fingerprint {
+ // Intern the new `DepNode`.
+ let dep_node_index = if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
+ // Determine the color and index of the new `DepNode`.
+ let (color, dep_node_index) = if let Some(current_fingerprint) = current_fingerprint
+ {
+ if current_fingerprint == data.previous.fingerprint_by_index(prev_index) {
if print_status {
eprintln!("[task::green] {:?}", key);
}
- DepNodeColor::Green(dep_node_index)
+
+ // This is a light green node: it existed in the previous compilation,
+ // its query was re-executed, and it has the same result as before.
+ let dep_node_index =
+ data.current.intern_light_green_node(&data.previous, prev_index, edges);
+
+ (DepNodeColor::Green(dep_node_index), dep_node_index)
} else {
if print_status {
eprintln!("[task::red] {:?}", key);
}
- DepNodeColor::Red
+
+ // This is a red node: it existed in the previous compilation, its query
+ // was re-executed, but it has a different result from before.
+ let dep_node_index = data.current.intern_red_node(
+ &data.previous,
+ prev_index,
+ edges,
+ current_fingerprint,
+ );
+
+ (DepNodeColor::Red, dep_node_index)
}
} else {
if print_status {
eprintln!("[task::unknown] {:?}", key);
}
- // Mark the node as Red if we can't hash the result
- DepNodeColor::Red
+
+ // This is a red node, effectively: it existed in the previous compilation
+ // session, its query was re-executed, but it doesn't compute a result hash
+ // (i.e. it represents a `no_hash` query), so we have no way of determining
+ // whether or not the result was the same as before.
+ let dep_node_index = data.current.intern_red_node(
+ &data.previous,
+ prev_index,
+ edges,
+ Fingerprint::ZERO,
+ );
+
+ (DepNodeColor::Red, dep_node_index)
};
debug_assert!(
);
data.colors.insert(prev_index, color);
- } else if print_status {
- eprintln!("[task::new] {:?}", key);
- }
+ dep_node_index
+ } else {
+ if print_status {
+ eprintln!("[task::new] {:?}", key);
+ }
+
+ // This is a new node: it didn't exist in the previous compilation session.
+ data.current.intern_new_node(
+ &data.previous,
+ key,
+ edges,
+ current_fingerprint.unwrap_or(Fingerprint::ZERO),
+ )
+ };
(result, dep_node_index)
} else {
+ // Incremental compilation is turned off. We just execute the task
+ // without tracking. We still provide a dep-node index that uniquely
+ // identifies the task so that we have a cheap way of referring to
+ // the query for self-profiling.
(task(cx, arg), self.next_virtual_depnode_index())
}
}
where
OP: FnOnce() -> R,
{
+ debug_assert!(!dep_kind.is_eval_always());
+
if let Some(ref data) = self.data {
let task_deps = Lock::new(TaskDeps::default());
-
let result = K::with_deps(Some(&task_deps), op);
let task_deps = task_deps.into_inner();
- let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps);
+ // The dep node indices are hashed here instead of hashing the dep nodes of the
+ // dependencies. These indices may refer to different nodes per session, but this isn't
+ // a problem here because we that ensure the final dep node hash is per session only by
+ // combining it with the per session random number `anon_id_seed`. This hash only need
+ // to map the dependencies to a single value on a per session basis.
+ let mut hasher = StableHasher::new();
+ task_deps.reads.hash(&mut hasher);
+
+ let target_dep_node = DepNode {
+ kind: dep_kind,
+ // Fingerprint::combine() is faster than sending Fingerprint
+ // through the StableHasher (at least as long as StableHasher
+ // is so slow).
+ hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+ };
+
+ let dep_node_index = data.current.intern_new_node(
+ &data.previous,
+ target_dep_node,
+ task_deps.reads,
+ Fingerprint::ZERO,
+ );
+
(result, dep_node_index)
} else {
(op(), self.next_virtual_depnode_index())
task: fn(Ctxt, A) -> R,
hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
) -> (R, DepNodeIndex) {
- self.with_task_impl(
- key,
- cx,
- arg,
- false,
- task,
- |_| None,
- |data, key, fingerprint, _| data.alloc_node(key, smallvec![], fingerprint),
- hash_result,
- )
+ self.with_task_impl(key, cx, arg, task, |_| None, hash_result)
}
#[inline]
- pub fn read(&self, v: DepNode<K>) {
+ pub fn read_index(&self, dep_node_index: DepNodeIndex) {
if let Some(ref data) = self.data {
- let map = data.current.node_to_node_index.get_shard_by_value(&v).lock();
- if let Some(dep_node_index) = map.get(&v).copied() {
- std::mem::drop(map);
- data.read_index(dep_node_index);
- } else {
- panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
- }
+ K::read_deps(|task_deps| {
+ if let Some(task_deps) = task_deps {
+ let mut task_deps = task_deps.lock();
+ let task_deps = &mut *task_deps;
+ if cfg!(debug_assertions) {
+ data.current.total_read_count.fetch_add(1, Relaxed);
+ }
+
+ // As long as we only have a low number of reads we can avoid doing a hash
+ // insert and potentially allocating/reallocating the hashmap
+ let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
+ task_deps.reads.iter().all(|other| *other != dep_node_index)
+ } else {
+ task_deps.read_set.insert(dep_node_index)
+ };
+ if new_read {
+ task_deps.reads.push(dep_node_index);
+ if task_deps.reads.len() == TASK_DEPS_READS_CAP {
+ // Fill `read_set` with what we have so far so we can use the hashset
+ // next time
+ task_deps.read_set.extend(task_deps.reads.iter().copied());
+ }
+
+ #[cfg(debug_assertions)]
+ {
+ if let Some(target) = task_deps.node {
+ if let Some(ref forbidden_edge) = data.current.forbidden_edge {
+ let src = self.dep_node_of(dep_node_index);
+ if forbidden_edge.test(&src, &target) {
+ panic!("forbidden edge {:?} -> {:?} created", src, target)
+ }
+ }
+ }
+ }
+ } else if cfg!(debug_assertions) {
+ data.current.total_duplicate_read_count.fetch_add(1, Relaxed);
+ }
+ }
+ })
}
}
#[inline]
- pub fn read_index(&self, dep_node_index: DepNodeIndex) {
- if let Some(ref data) = self.data {
- data.read_index(dep_node_index);
- }
+ pub fn dep_node_index_of(&self, dep_node: &DepNode<K>) -> DepNodeIndex {
+ self.dep_node_index_of_opt(dep_node).unwrap()
}
#[inline]
- pub fn dep_node_index_of(&self, dep_node: &DepNode<K>) -> DepNodeIndex {
- self.data
- .as_ref()
- .unwrap()
- .current
- .node_to_node_index
- .get_shard_by_value(dep_node)
- .lock()
- .get(dep_node)
- .cloned()
- .unwrap()
+ pub fn dep_node_index_of_opt(&self, dep_node: &DepNode<K>) -> Option<DepNodeIndex> {
+ let data = self.data.as_ref().unwrap();
+ let current = &data.current;
+
+ if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) {
+ current.prev_index_to_index.lock()[prev_index]
+ } else {
+ current.new_node_to_index.get_shard_by_value(dep_node).lock().get(dep_node).copied()
+ }
}
#[inline]
pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
- if let Some(ref data) = self.data {
- data.current
- .node_to_node_index
- .get_shard_by_value(&dep_node)
- .lock()
- .contains_key(dep_node)
- } else {
- false
+ self.data.is_some() && self.dep_node_index_of_opt(dep_node).is_some()
+ }
+
+ #[inline]
+ pub fn dep_node_of(&self, dep_node_index: DepNodeIndex) -> DepNode<K> {
+ let data = self.data.as_ref().unwrap();
+ let previous = &data.previous;
+ let data = data.current.data.lock();
+
+ match data.hybrid_indices[dep_node_index].into() {
+ HybridIndex::New(new_index) => data.new.nodes[new_index],
+ HybridIndex::Red(red_index) => previous.index_to_node(data.red.node_indices[red_index]),
+ HybridIndex::LightGreen(light_green_index) => {
+ previous.index_to_node(data.light_green.node_indices[light_green_index])
+ }
+ HybridIndex::DarkGreen(prev_index) => previous.index_to_node(prev_index),
}
}
#[inline]
pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint {
- let data = self.data.as_ref().expect("dep graph enabled").current.data.lock();
- data[dep_node_index].fingerprint
+ let data = self.data.as_ref().unwrap();
+ let previous = &data.previous;
+ let data = data.current.data.lock();
+
+ match data.hybrid_indices[dep_node_index].into() {
+ HybridIndex::New(new_index) => data.new.fingerprints[new_index],
+ HybridIndex::Red(red_index) => data.red.fingerprints[red_index],
+ HybridIndex::LightGreen(light_green_index) => {
+ previous.fingerprint_by_index(data.light_green.node_indices[light_green_index])
+ }
+ HybridIndex::DarkGreen(prev_index) => previous.fingerprint_by_index(prev_index),
+ }
}
pub fn prev_fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
}
}
- pub fn serialize(&self) -> SerializedDepGraph<K> {
- let data = self.data.as_ref().unwrap().current.data.lock();
+ fn edge_count(&self, node_data: &LockGuard<'_, DepNodeData<K>>) -> usize {
+ let data = self.data.as_ref().unwrap();
+ let previous = &data.previous;
- let fingerprints: IndexVec<SerializedDepNodeIndex, _> =
- data.iter().map(|d| d.fingerprint).collect();
- let nodes: IndexVec<SerializedDepNodeIndex, _> = data.iter().map(|d| d.node).collect();
+ let mut edge_count = node_data.unshared_edges.len();
- let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum();
+ for &hybrid_index in node_data.hybrid_indices.iter() {
+ if let HybridIndex::DarkGreen(prev_index) = hybrid_index.into() {
+ edge_count += previous.edge_targets_from(prev_index).len()
+ }
+ }
- let mut edge_list_indices = IndexVec::with_capacity(nodes.len());
- let mut edge_list_data = Vec::with_capacity(total_edge_count);
+ edge_count
+ }
- for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) {
- let start = edge_list_data.len() as u32;
- // This should really just be a memcpy :/
- edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index())));
- let end = edge_list_data.len() as u32;
+ pub fn serialize(&self) -> SerializedDepGraph<K> {
+ type SDNI = SerializedDepNodeIndex;
- debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len());
- edge_list_indices.push((start, end));
+ let data = self.data.as_ref().unwrap();
+ let previous = &data.previous;
+
+ // Note locking order: `prev_index_to_index`, then `data`.
+ let prev_index_to_index = data.current.prev_index_to_index.lock();
+ let data = data.current.data.lock();
+ let node_count = data.hybrid_indices.len();
+ let edge_count = self.edge_count(&data);
+
+ let mut nodes = IndexVec::with_capacity(node_count);
+ let mut fingerprints = IndexVec::with_capacity(node_count);
+ let mut edge_list_indices = IndexVec::with_capacity(node_count);
+ let mut edge_list_data = Vec::with_capacity(edge_count);
+
+ // `rustc_middle::ty::query::OnDiskCache` expects nodes to be in
+ // `DepNodeIndex` order. The edges in `edge_list_data`, on the other
+ // hand, don't need to be in a particular order, as long as each node
+ // can reference its edges as a contiguous range within it. This is why
+ // we're able to copy `unshared_edges` directly into `edge_list_data`.
+ // It meets the above requirements, and each non-dark-green node already
+ // knows the range of edges to reference within it, which they'll push
+ // onto `edge_list_indices`. Dark green nodes, however, don't have their
+ // edges in `unshared_edges`, so need to add them to `edge_list_data`.
+
+ edge_list_data.extend(data.unshared_edges.iter().map(|i| SDNI::new(i.index())));
+
+ for &hybrid_index in data.hybrid_indices.iter() {
+ match hybrid_index.into() {
+ HybridIndex::New(i) => {
+ let new = &data.new;
+ nodes.push(new.nodes[i]);
+ fingerprints.push(new.fingerprints[i]);
+ let edges = &new.edges[i];
+ edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
+ }
+ HybridIndex::Red(i) => {
+ let red = &data.red;
+ nodes.push(previous.index_to_node(red.node_indices[i]));
+ fingerprints.push(red.fingerprints[i]);
+ let edges = &red.edges[i];
+ edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
+ }
+ HybridIndex::LightGreen(i) => {
+ let lg = &data.light_green;
+ nodes.push(previous.index_to_node(lg.node_indices[i]));
+ fingerprints.push(previous.fingerprint_by_index(lg.node_indices[i]));
+ let edges = &lg.edges[i];
+ edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
+ }
+ HybridIndex::DarkGreen(prev_index) => {
+ nodes.push(previous.index_to_node(prev_index));
+ fingerprints.push(previous.fingerprint_by_index(prev_index));
+
+ let edges_iter = previous
+ .edge_targets_from(prev_index)
+ .iter()
+ .map(|&dst| prev_index_to_index[dst].as_ref().unwrap());
+
+ let start = edge_list_data.len() as u32;
+ edge_list_data.extend(edges_iter.map(|i| SDNI::new(i.index())));
+ let end = edge_list_data.len() as u32;
+ edge_list_indices.push((start, end));
+ }
+ }
}
+ debug_assert_eq!(nodes.len(), node_count);
+ debug_assert_eq!(fingerprints.len(), node_count);
+ debug_assert_eq!(edge_list_indices.len(), node_count);
+ debug_assert_eq!(edge_list_data.len(), edge_count);
debug_assert!(edge_list_data.len() <= u32::MAX as usize);
- debug_assert_eq!(edge_list_data.len(), total_edge_count);
SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }
}
#[cfg(not(parallel_compiler))]
{
- debug_assert!(
- !data
- .current
- .node_to_node_index
- .get_shard_by_value(dep_node)
- .lock()
- .contains_key(dep_node)
- );
+ debug_assert!(!self.dep_node_exists(dep_node));
debug_assert!(data.colors.get(prev_dep_node_index).is_none());
}
// We never try to mark eval_always nodes as green
debug_assert!(!dep_node.kind.is_eval_always());
- data.previous.debug_assert_eq(prev_dep_node_index, *dep_node);
+ debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
- let mut current_deps = SmallVec::new();
-
for &dep_dep_node_index in prev_deps {
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
match dep_dep_node_color {
- Some(DepNodeColor::Green(node_index)) => {
+ Some(DepNodeColor::Green(_)) => {
// This dependency has been marked as green before, we are
// still fine and can continue with checking the other
// dependencies.
"try_mark_previous_green({:?}) --- found dependency {:?} to \
be immediately green",
dep_node,
- data.previous.debug_dep_node(dep_dep_node_index),
+ data.previous.index_to_node(dep_dep_node_index)
);
- current_deps.push(node_index);
}
Some(DepNodeColor::Red) => {
// We found a dependency the value of which has changed
"try_mark_previous_green({:?}) - END - dependency {:?} was \
immediately red",
dep_node,
- data.previous.debug_dep_node(dep_dep_node_index)
+ data.previous.index_to_node(dep_dep_node_index)
);
return None;
}
None => {
- let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index, tcx);
+ let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
// We don't know the state of this dependency. If it isn't
// an eval_always node, let's try to mark it green recursively.
dep_dep_node_index,
dep_dep_node,
);
- if let Some(node_index) = node_index {
+ if node_index.is_some() {
debug!(
"try_mark_previous_green({:?}) --- managed to MARK \
dependency {:?} as green",
dep_node, dep_dep_node
);
- current_deps.push(node_index);
continue;
}
}
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
match dep_dep_node_color {
- Some(DepNodeColor::Green(node_index)) => {
+ Some(DepNodeColor::Green(_)) => {
debug!(
"try_mark_previous_green({:?}) --- managed to \
FORCE dependency {:?} to green",
dep_node, dep_dep_node
);
- current_deps.push(node_index);
}
Some(DepNodeColor::Red) => {
debug!(
// There may be multiple threads trying to mark the same dep node green concurrently
let dep_node_index = {
- // Copy the fingerprint from the previous graph,
- // so we don't have to recompute it
- let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index);
-
// We allocating an entry for the node in the current dependency graph and
// adding all the appropriate edges imported from the previous graph
- data.current.intern_node(*dep_node, current_deps, fingerprint)
+ data.current.intern_dark_green_node(&data.previous, prev_dep_node_index)
};
// ... emitting any stored diagnostic ...
for prev_index in data.colors.values.indices() {
match data.colors.get(prev_index) {
Some(DepNodeColor::Green(_)) => {
- let dep_node = data.previous.index_to_node(prev_index, tcx);
+ let dep_node = data.previous.index_to_node(prev_index);
tcx.try_load_from_on_disk_cache(&dep_node);
}
None | Some(DepNodeColor::Red) => {
}
}
+ // Register reused dep nodes (i.e. nodes we've marked red or green) with the context.
+ pub fn register_reused_dep_nodes<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
+ let data = self.data.as_ref().unwrap();
+ for prev_index in data.colors.values.indices() {
+ match data.colors.get(prev_index) {
+ Some(DepNodeColor::Red) | Some(DepNodeColor::Green(_)) => {
+ let dep_node = data.previous.index_to_node(prev_index);
+ tcx.register_reused_dep_node(&dep_node);
+ }
+ None => {}
+ }
+ }
+ }
+
fn next_virtual_depnode_index(&self) -> DepNodeIndex {
let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
DepNodeIndex::from_u32(index)
pub saved_file: Option<String>,
}
-#[derive(Clone)]
+// The maximum value of the follow index types leaves the upper two bits unused
+// so that we can store multiple index types in `CompressedHybridIndex`, and use
+// those bits to encode which index type it contains.
+
+// Index type for `NewDepNodeData`.
+rustc_index::newtype_index! {
+ struct NewDepNodeIndex {
+ MAX = 0x7FFF_FFFF
+ }
+}
+
+// Index type for `RedDepNodeData`.
+rustc_index::newtype_index! {
+ struct RedDepNodeIndex {
+ MAX = 0x7FFF_FFFF
+ }
+}
+
+// Index type for `LightGreenDepNodeData`.
+rustc_index::newtype_index! {
+ struct LightGreenDepNodeIndex {
+ MAX = 0x7FFF_FFFF
+ }
+}
+
+/// Compressed representation of `HybridIndex` enum. Bits unused by the
+/// contained index types are used to encode which index type it contains.
+#[derive(Copy, Clone)]
+struct CompressedHybridIndex(u32);
+
+impl CompressedHybridIndex {
+ const NEW_TAG: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000;
+ const RED_TAG: u32 = 0b0100_0000_0000_0000_0000_0000_0000_0000;
+ const LIGHT_GREEN_TAG: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000;
+ const DARK_GREEN_TAG: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000;
+
+ const TAG_MASK: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000;
+ const INDEX_MASK: u32 = !Self::TAG_MASK;
+}
+
+impl From<NewDepNodeIndex> for CompressedHybridIndex {
+ #[inline]
+ fn from(index: NewDepNodeIndex) -> Self {
+ CompressedHybridIndex(Self::NEW_TAG | index.as_u32())
+ }
+}
+
+impl From<RedDepNodeIndex> for CompressedHybridIndex {
+ #[inline]
+ fn from(index: RedDepNodeIndex) -> Self {
+ CompressedHybridIndex(Self::RED_TAG | index.as_u32())
+ }
+}
+
+impl From<LightGreenDepNodeIndex> for CompressedHybridIndex {
+ #[inline]
+ fn from(index: LightGreenDepNodeIndex) -> Self {
+ CompressedHybridIndex(Self::LIGHT_GREEN_TAG | index.as_u32())
+ }
+}
+
+impl From<SerializedDepNodeIndex> for CompressedHybridIndex {
+ #[inline]
+ fn from(index: SerializedDepNodeIndex) -> Self {
+ CompressedHybridIndex(Self::DARK_GREEN_TAG | index.as_u32())
+ }
+}
+
+/// Contains an index into one of several node data collections. Elsewhere, we
+/// store `CompressedHyridIndex` instead of this to save space, but convert to
+/// this type during processing to take advantage of the enum match ergonomics.
+enum HybridIndex {
+ New(NewDepNodeIndex),
+ Red(RedDepNodeIndex),
+ LightGreen(LightGreenDepNodeIndex),
+ DarkGreen(SerializedDepNodeIndex),
+}
+
+impl From<CompressedHybridIndex> for HybridIndex {
+ #[inline]
+ fn from(hybrid_index: CompressedHybridIndex) -> Self {
+ let index = hybrid_index.0 & CompressedHybridIndex::INDEX_MASK;
+
+ match hybrid_index.0 & CompressedHybridIndex::TAG_MASK {
+ CompressedHybridIndex::NEW_TAG => HybridIndex::New(NewDepNodeIndex::from_u32(index)),
+ CompressedHybridIndex::RED_TAG => HybridIndex::Red(RedDepNodeIndex::from_u32(index)),
+ CompressedHybridIndex::LIGHT_GREEN_TAG => {
+ HybridIndex::LightGreen(LightGreenDepNodeIndex::from_u32(index))
+ }
+ CompressedHybridIndex::DARK_GREEN_TAG => {
+ HybridIndex::DarkGreen(SerializedDepNodeIndex::from_u32(index))
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+
+// Index type for `DepNodeData`'s edges.
+rustc_index::newtype_index! {
+ struct EdgeIndex { .. }
+}
+
+/// Data for nodes in the current graph, divided into different collections
+/// based on their presence in the previous graph, and if present, their color.
+/// We divide nodes this way because different types of nodes are able to share
+/// more or less data with the previous graph.
+///
+/// To enable more sharing, we distinguish between two kinds of green nodes.
+/// Light green nodes are nodes in the previous graph that have been marked
+/// green because we re-executed their queries and the results were the same as
+/// in the previous session. Dark green nodes are nodes in the previous graph
+/// that have been marked green because we were able to mark all of their
+/// dependencies green.
+///
+/// Both light and dark green nodes can share the dep node and fingerprint with
+/// the previous graph, but for light green nodes, we can't be sure that the
+/// edges may be shared without comparing them against the previous edges, so we
+/// store them directly (an approach in which we compare edges with the previous
+/// edges to see if they can be shared was evaluated, but was not found to be
+/// very profitable).
+///
+/// For dark green nodes, we can share everything with the previous graph, which
+/// is why the `HybridIndex::DarkGreen` enum variant contains the index of the
+/// node in the previous graph, and why we don't have a separate collection for
+/// dark green node data--the collection is the `PreviousDepGraph` itself.
+///
+/// (Note that for dark green nodes, the edges in the previous graph
+/// (`SerializedDepNodeIndex`s) must be converted to edges in the current graph
+/// (`DepNodeIndex`s). `CurrentDepGraph` contains `prev_index_to_index`, which
+/// can perform this conversion. It should always be possible, as by definition,
+/// a dark green node is one whose dependencies from the previous session have
+/// all been marked green--which means `prev_index_to_index` contains them.)
+///
+/// Node data is stored in parallel vectors to eliminate the padding between
+/// elements that would be needed to satisfy alignment requirements of the
+/// structure that would contain all of a node's data. We could group tightly
+/// packing subsets of node data together and use fewer vectors, but for
+/// consistency's sake, we use separate vectors for each piece of data.
struct DepNodeData<K> {
- node: DepNode<K>,
- edges: EdgesVec,
- fingerprint: Fingerprint,
+ /// Data for nodes not in previous graph.
+ new: NewDepNodeData<K>,
+
+ /// Data for nodes in previous graph that have been marked red.
+ red: RedDepNodeData,
+
+ /// Data for nodes in previous graph that have been marked light green.
+ light_green: LightGreenDepNodeData,
+
+ // Edges for all nodes other than dark-green ones. Edges for each node
+ // occupy a contiguous region of this collection, which a node can reference
+ // using two indices. Storing edges this way rather than using an `EdgesVec`
+ // for each node reduces memory consumption by a not insignificant amount
+ // when compiling large crates. The downside is that we have to copy into
+ // this collection the edges from the `EdgesVec`s that are built up during
+ // query execution. But this is mostly balanced out by the more efficient
+ // implementation of `DepGraph::serialize` enabled by this representation.
+ unshared_edges: IndexVec<EdgeIndex, DepNodeIndex>,
+
+ /// Mapping from `DepNodeIndex` to an index into a collection above.
+ /// Indicates which of the above collections contains a node's data.
+ ///
+ /// This collection is wasteful in time and space during incr-full builds,
+ /// because for those, all nodes are new. However, the waste is relatively
+ /// small, and the maintenance cost of avoiding using this for incr-full
+ /// builds is somewhat high and prone to bugginess. It does not seem worth
+ /// it at the time of this writing, but we may want to revisit the idea.
+ hybrid_indices: IndexVec<DepNodeIndex, CompressedHybridIndex>,
+}
+
+/// Data for nodes not in previous graph. Since we cannot share any data with
+/// the previous graph, so we must store all of such a node's data here.
+struct NewDepNodeData<K> {
+ nodes: IndexVec<NewDepNodeIndex, DepNode<K>>,
+ edges: IndexVec<NewDepNodeIndex, Range<EdgeIndex>>,
+ fingerprints: IndexVec<NewDepNodeIndex, Fingerprint>,
}
-/// `CurrentDepGraph` stores the dependency graph for the current session.
-/// It will be populated as we run queries or tasks.
+/// Data for nodes in previous graph that have been marked red. We can share the
+/// dep node with the previous graph, but the edges may be different, and the
+/// fingerprint is known to be different, so we store the latter two directly.
+struct RedDepNodeData {
+ node_indices: IndexVec<RedDepNodeIndex, SerializedDepNodeIndex>,
+ edges: IndexVec<RedDepNodeIndex, Range<EdgeIndex>>,
+ fingerprints: IndexVec<RedDepNodeIndex, Fingerprint>,
+}
+
+/// Data for nodes in previous graph that have been marked green because we
+/// re-executed their queries and the results were the same as in the previous
+/// session. We can share the dep node and the fingerprint with the previous
+/// graph, but the edges may be different, so we store them directly.
+struct LightGreenDepNodeData {
+ node_indices: IndexVec<LightGreenDepNodeIndex, SerializedDepNodeIndex>,
+ edges: IndexVec<LightGreenDepNodeIndex, Range<EdgeIndex>>,
+}
+
+/// `CurrentDepGraph` stores the dependency graph for the current session. It
+/// will be populated as we run queries or tasks. We never remove nodes from the
+/// graph: they are only added.
///
-/// The nodes in it are identified by an index (`DepNodeIndex`).
-/// The data for each node is stored in its `DepNodeData`, found in the `data` field.
+/// The nodes in it are identified by a `DepNodeIndex`. Internally, this maps to
+/// a `HybridIndex`, which identifies which collection in the `data` field
+/// contains a node's data. Which collection is used for a node depends on
+/// whether the node was present in the `PreviousDepGraph`, and if so, the color
+/// of the node. Each type of node can share more or less data with the previous
+/// graph. When possible, we can store just the index of the node in the
+/// previous graph, rather than duplicating its data in our own collections.
+/// This is important, because these graph structures are some of the largest in
+/// the compiler.
///
-/// We never remove nodes from the graph: they are only added.
+/// For the same reason, we also avoid storing `DepNode`s more than once as map
+/// keys. The `new_node_to_index` map only contains nodes not in the previous
+/// graph, and we map nodes in the previous graph to indices via a two-step
+/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
+/// and the `prev_index_to_index` vector (which is more compact and faster than
+/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
///
-/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are
-/// locked separately. Operations that take a `DepNodeIndex` typically just access
-/// the data field.
+/// This struct uses three locks internally. The `data`, `new_node_to_index`,
+/// and `prev_index_to_index` fields are locked separately. Operations that take
+/// a `DepNodeIndex` typically just access the `data` field.
///
-/// The only operation that must manipulate both locks is adding new nodes, in which case
-/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted,
-/// acquire the lock on `data.`
+/// We only need to manipulate at most two locks simultaneously:
+/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When
+/// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index`
+/// first, and `data` second.
pub(super) struct CurrentDepGraph<K> {
- data: Lock<IndexVec<DepNodeIndex, DepNodeData<K>>>,
- node_to_node_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>,
+ data: Lock<DepNodeData<K>>,
+ new_node_to_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>,
+ prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>,
/// Used to trap when a specific edge is added to the graph.
/// This is used for debug purposes and is only active with `debug_assertions`.
// Pre-allocate the dep node structures. We over-allocate a little so
// that we hopefully don't have to re-allocate during this compilation
- // session. The over-allocation is 2% plus a small constant to account
- // for the fact that in very small crates 2% might not be enough.
- let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200;
+ // session. The over-allocation for new nodes is 2% plus a small
+ // constant to account for the fact that in very small crates 2% might
+ // not be enough. The allocation for red and green node data doesn't
+ // include a constant, as we don't want to allocate anything for these
+ // structures during full incremental builds, where they aren't used.
+ //
+ // These estimates are based on the distribution of node and edge counts
+ // seen in rustc-perf benchmarks, adjusted somewhat to account for the
+ // fact that these benchmarks aren't perfectly representative.
+ //
+ // FIXME Use a collection type that doesn't copy node and edge data and
+ // grow multiplicatively on reallocation. Without such a collection or
+ // solution having the same effect, there is a performance hazard here
+ // in both time and space, as growing these collections means copying a
+ // large amount of data and doubling already large buffer capacities. A
+ // solution for this will also mean that it's less important to get
+ // these estimates right.
+ let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200;
+ let red_node_count_estimate = (prev_graph_node_count * 3) / 100;
+ let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100;
+ let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate;
+
+ let average_edges_per_node_estimate = 6;
+ let unshared_edge_count_estimate = average_edges_per_node_estimate
+ * (new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate);
+
+ // We store a large collection of these in `prev_index_to_index` during
+ // non-full incremental builds, and want to ensure that the element size
+ // doesn't inadvertently increase.
+ static_assert_size!(Option<DepNodeIndex>, 4);
CurrentDepGraph {
- data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)),
- node_to_node_index: Sharded::new(|| {
+ data: Lock::new(DepNodeData {
+ new: NewDepNodeData {
+ nodes: IndexVec::with_capacity(new_node_count_estimate),
+ edges: IndexVec::with_capacity(new_node_count_estimate),
+ fingerprints: IndexVec::with_capacity(new_node_count_estimate),
+ },
+ red: RedDepNodeData {
+ node_indices: IndexVec::with_capacity(red_node_count_estimate),
+ edges: IndexVec::with_capacity(red_node_count_estimate),
+ fingerprints: IndexVec::with_capacity(red_node_count_estimate),
+ },
+ light_green: LightGreenDepNodeData {
+ node_indices: IndexVec::with_capacity(light_green_node_count_estimate),
+ edges: IndexVec::with_capacity(light_green_node_count_estimate),
+ },
+ unshared_edges: IndexVec::with_capacity(unshared_edge_count_estimate),
+ hybrid_indices: IndexVec::with_capacity(total_node_count_estimate),
+ }),
+ new_node_to_index: Sharded::new(|| {
FxHashMap::with_capacity_and_hasher(
new_node_count_estimate / sharded::SHARDS,
Default::default(),
)
}),
+ prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
anon_id_seed: stable_hasher.finish(),
forbidden_edge,
total_read_count: AtomicU64::new(0),
}
}
- fn complete_task(
+ fn intern_new_node(
&self,
- node: DepNode<K>,
- task_deps: TaskDeps<K>,
+ prev_graph: &PreviousDepGraph<K>,
+ dep_node: DepNode<K>,
+ edges: EdgesVec,
fingerprint: Fingerprint,
) -> DepNodeIndex {
- self.alloc_node(node, task_deps.reads, fingerprint)
- }
-
- fn complete_anon_task(&self, kind: K, task_deps: TaskDeps<K>) -> DepNodeIndex {
- debug_assert!(!kind.is_eval_always());
-
- let mut hasher = StableHasher::new();
-
- // The dep node indices are hashed here instead of hashing the dep nodes of the
- // dependencies. These indices may refer to different nodes per session, but this isn't
- // a problem here because we that ensure the final dep node hash is per session only by
- // combining it with the per session random number `anon_id_seed`. This hash only need
- // to map the dependencies to a single value on a per session basis.
- task_deps.reads.hash(&mut hasher);
-
- let target_dep_node = DepNode {
- kind,
-
- // Fingerprint::combine() is faster than sending Fingerprint
- // through the StableHasher (at least as long as StableHasher
- // is so slow).
- hash: self.anon_id_seed.combine(hasher.finish()).into(),
- };
+ debug_assert!(
+ prev_graph.node_to_index_opt(&dep_node).is_none(),
+ "node in previous graph should be interned using one \
+ of `intern_red_node`, `intern_light_green_node`, etc."
+ );
- self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO)
+ match self.new_node_to_index.get_shard_by_value(&dep_node).lock().entry(dep_node) {
+ Entry::Occupied(entry) => *entry.get(),
+ Entry::Vacant(entry) => {
+ let data = &mut *self.data.lock();
+ let new_index = data.new.nodes.push(dep_node);
+ add_edges(&mut data.unshared_edges, &mut data.new.edges, edges);
+ data.new.fingerprints.push(fingerprint);
+ let dep_node_index = data.hybrid_indices.push(new_index.into());
+ entry.insert(dep_node_index);
+ dep_node_index
+ }
+ }
}
- fn alloc_node(
+ fn intern_red_node(
&self,
- dep_node: DepNode<K>,
+ prev_graph: &PreviousDepGraph<K>,
+ prev_index: SerializedDepNodeIndex,
edges: EdgesVec,
fingerprint: Fingerprint,
) -> DepNodeIndex {
- debug_assert!(
- !self.node_to_node_index.get_shard_by_value(&dep_node).lock().contains_key(&dep_node)
- );
- self.intern_node(dep_node, edges, fingerprint)
+ self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
+
+ let mut prev_index_to_index = self.prev_index_to_index.lock();
+
+ match prev_index_to_index[prev_index] {
+ Some(dep_node_index) => dep_node_index,
+ None => {
+ let data = &mut *self.data.lock();
+ let red_index = data.red.node_indices.push(prev_index);
+ add_edges(&mut data.unshared_edges, &mut data.red.edges, edges);
+ data.red.fingerprints.push(fingerprint);
+ let dep_node_index = data.hybrid_indices.push(red_index.into());
+ prev_index_to_index[prev_index] = Some(dep_node_index);
+ dep_node_index
+ }
+ }
}
- fn intern_node(
+ fn intern_light_green_node(
&self,
- dep_node: DepNode<K>,
+ prev_graph: &PreviousDepGraph<K>,
+ prev_index: SerializedDepNodeIndex,
edges: EdgesVec,
- fingerprint: Fingerprint,
) -> DepNodeIndex {
- match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) {
- Entry::Occupied(entry) => *entry.get(),
- Entry::Vacant(entry) => {
- let mut data = self.data.lock();
- let dep_node_index = DepNodeIndex::new(data.len());
- data.push(DepNodeData { node: dep_node, edges, fingerprint });
- entry.insert(dep_node_index);
+ self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
+
+ let mut prev_index_to_index = self.prev_index_to_index.lock();
+
+ match prev_index_to_index[prev_index] {
+ Some(dep_node_index) => dep_node_index,
+ None => {
+ let data = &mut *self.data.lock();
+ let light_green_index = data.light_green.node_indices.push(prev_index);
+ add_edges(&mut data.unshared_edges, &mut data.light_green.edges, edges);
+ let dep_node_index = data.hybrid_indices.push(light_green_index.into());
+ prev_index_to_index[prev_index] = Some(dep_node_index);
dep_node_index
}
}
}
-}
-impl<K: DepKind> DepGraphData<K> {
- #[inline(never)]
- fn read_index(&self, source: DepNodeIndex) {
- K::read_deps(|task_deps| {
- if let Some(task_deps) = task_deps {
- let mut task_deps = task_deps.lock();
- let task_deps = &mut *task_deps;
- if cfg!(debug_assertions) {
- self.current.total_read_count.fetch_add(1, Relaxed);
- }
+ fn intern_dark_green_node(
+ &self,
+ prev_graph: &PreviousDepGraph<K>,
+ prev_index: SerializedDepNodeIndex,
+ ) -> DepNodeIndex {
+ self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
- // As long as we only have a low number of reads we can avoid doing a hash
- // insert and potentially allocating/reallocating the hashmap
- let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
- task_deps.reads.iter().all(|other| *other != source)
- } else {
- task_deps.read_set.insert(source)
- };
- if new_read {
- task_deps.reads.push(source);
- if task_deps.reads.len() == TASK_DEPS_READS_CAP {
- // Fill `read_set` with what we have so far so we can use the hashset next
- // time
- task_deps.read_set.extend(task_deps.reads.iter().copied());
- }
+ let mut prev_index_to_index = self.prev_index_to_index.lock();
- #[cfg(debug_assertions)]
- {
- if let Some(target) = task_deps.node {
- let data = self.current.data.lock();
- if let Some(ref forbidden_edge) = self.current.forbidden_edge {
- let source = data[source].node;
- if forbidden_edge.test(&source, &target) {
- panic!("forbidden edge {:?} -> {:?} created", source, target)
- }
- }
- }
- }
- } else if cfg!(debug_assertions) {
- self.current.total_duplicate_read_count.fetch_add(1, Relaxed);
- }
+ match prev_index_to_index[prev_index] {
+ Some(dep_node_index) => dep_node_index,
+ None => {
+ let mut data = self.data.lock();
+ let dep_node_index = data.hybrid_indices.push(prev_index.into());
+ prev_index_to_index[prev_index] = Some(dep_node_index);
+ dep_node_index
}
- })
+ }
+ }
+
+ #[inline]
+ fn debug_assert_not_in_new_nodes(
+ &self,
+ prev_graph: &PreviousDepGraph<K>,
+ prev_index: SerializedDepNodeIndex,
+ ) {
+ let node = &prev_graph.index_to_node(prev_index);
+ debug_assert!(
+ !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node),
+ "node from previous graph present in new node collection"
+ );
}
}
+#[inline]
+fn add_edges<I: Idx>(
+ edges: &mut IndexVec<EdgeIndex, DepNodeIndex>,
+ edge_indices: &mut IndexVec<I, Range<EdgeIndex>>,
+ new_edges: EdgesVec,
+) {
+ let start = edges.next_index();
+ edges.extend(new_edges);
+ let end = edges.next_index();
+ edge_indices.push(start..end);
+}
+
/// The capacity of the `reads` field `SmallVec`
const TASK_DEPS_READS_CAP: usize = 8;
type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
-use rustc_span::def_id::DefPathHash;
use std::fmt;
use std::hash::Hash;
/// Try to force a dep node to execute and see if it's green.
fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
- fn register_reused_dep_path_hash(&self, hash: DefPathHash);
+ fn register_reused_dep_node(&self, dep_node: &DepNode<Self::DepKind>);
/// Return whether the current session is tainted by errors.
fn has_errors_or_delayed_span_bugs(&self) -> bool;
use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
use super::{DepKind, DepNode};
-use crate::dep_graph::DepContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
-use rustc_span::def_id::DefPathHash;
#[derive(Debug, Encodable, Decodable)]
pub struct PreviousDepGraph<K: DepKind> {
}
#[inline]
- pub fn index_to_node<CTX: DepContext<DepKind = K>>(
- &self,
- dep_node_index: SerializedDepNodeIndex,
- tcx: CTX,
- ) -> DepNode<K> {
- let dep_node = self.data.nodes[dep_node_index];
- // We have just loaded a deserialized `DepNode` from the previous
- // compilation session into the current one. If this was a foreign `DefId`,
- // then we stored additional information in the incr comp cache when we
- // initially created its fingerprint (see `DepNodeParams::to_fingerprint`)
- // We won't be calling `to_fingerprint` again for this `DepNode` (we no longer
- // have the original value), so we need to copy over this additional information
- // from the old incremental cache into the new cache that we serialize
- // and the end of this compilation session.
- if dep_node.kind.can_reconstruct_query_key() {
- tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into()));
- }
- dep_node
- }
-
- /// When debug assertions are enabled, asserts that the dep node at `dep_node_index` is equal to `dep_node`.
- /// This method should be preferred over manually calling `index_to_node`.
- /// Calls to `index_to_node` may affect global state, so gating a call
- /// to `index_to_node` on debug assertions could cause behavior changes when debug assertions
- /// are enabled.
- #[inline]
- pub fn debug_assert_eq(&self, dep_node_index: SerializedDepNodeIndex, dep_node: DepNode<K>) {
- debug_assert_eq!(self.data.nodes[dep_node_index], dep_node);
- }
-
- /// Obtains a debug-printable version of the `DepNode`.
- /// See `debug_assert_eq` for why this should be preferred over manually
- /// calling `dep_node_index`
- pub fn debug_dep_node(&self, dep_node_index: SerializedDepNodeIndex) -> impl std::fmt::Debug {
- // We're returning the `DepNode` without calling `register_reused_dep_path_hash`,
- // but `impl Debug` return type means that it can only be used for debug printing.
- // So, there's no risk of calls trying to create new dep nodes that have this
- // node as a dependency
+ pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
self.data.nodes[dep_node_index]
}
}
impl<K: DepKind> DepGraphQuery<K> {
- pub fn new(nodes: &[DepNode<K>], edges: &[(DepNode<K>, DepNode<K>)]) -> DepGraphQuery<K> {
- let mut graph = Graph::with_capacity(nodes.len(), edges.len());
+ pub fn new(
+ nodes: &[DepNode<K>],
+ edge_list_indices: &[(usize, usize)],
+ edge_list_data: &[usize],
+ ) -> DepGraphQuery<K> {
+ let mut graph = Graph::with_capacity(nodes.len(), edge_list_data.len());
let mut indices = FxHashMap::default();
for node in nodes {
indices.insert(*node, graph.add_node(*node));
}
- for &(ref source, ref target) in edges {
- let source = indices[source];
- let target = indices[target];
- graph.add_edge(source, target, ());
+ for (source, &(start, end)) in edge_list_indices.iter().enumerate() {
+ for &target in &edge_list_data[start..end] {
+ let source = indices[&nodes[source]];
+ let target = indices[&nodes[target]];
+ graph.add_edge(source, target, ());
+ }
}
DepGraphQuery { graph, indices }
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_index::vec::IndexVec;
+// The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
+// unused so that we can store multiple index types in `CompressedHybridIndex`,
+// and use those bits to encode which index type it contains.
rustc_index::newtype_index! {
- pub struct SerializedDepNodeIndex { .. }
+ pub struct SerializedDepNodeIndex {
+ MAX = 0x7FFF_FFFF
+ }
}
/// Data for use when recompiling the **current crate**.
crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
match res {
- Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id),
+ Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)),
Res::NonMacroAttr(attr_kind) => Some(self.non_macro_attr(attr_kind.is_used())),
_ => None,
}
}
- crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option<Lrc<SyntaxExtension>> {
+ crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Lrc<SyntaxExtension> {
if let Some(ext) = self.macro_map.get(&def_id) {
- return Some(ext.clone());
+ return ext.clone();
}
let ext = Lrc::new(match self.cstore().load_macro_untracked(def_id, &self.session) {
});
self.macro_map.insert(def_id, ext.clone());
- Some(ext)
+ ext
}
crate fn build_reduced_graph(
let field_names = vdata
.fields()
.iter()
- .map(|field| respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name)))
+ .map(|field| respan(field.span, field.ident.map_or(kw::Empty, |ident| ident.name)))
.collect();
self.insert_field_names(def_id, field_names);
}
ModuleKind::Block(..) => unreachable!(),
};
// HACK(eddyb) unclear how good this is, but keeping `$crate`
- // in `source` breaks `src/test/compile-fail/import-crate-var.rs`,
+ // in `source` breaks `src/test/ui/imports/import-crate-var.rs`,
// while the current crate doesn't have a valid `crate_name`.
- if crate_name != kw::Invalid {
+ if crate_name != kw::Empty {
// `crate_name` should not be interpreted as relative.
module_path.push(Segment {
ident: Ident { name: kw::PathRoot, span: source.ident.span },
/// Constructs the reduced graph for one item.
fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
- if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Invalid {
+ if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty {
// Fake crate root item from expand.
return;
}
// information we encapsulate into, the better
let def_data = match &i.kind {
ItemKind::Impl { .. } => DefPathData::Impl,
- ItemKind::Mod(..) if i.ident.name == kw::Invalid => {
+ ItemKind::Mod(..) if i.ident.name == kw::Empty => {
// Fake crate root item from expand.
return visit::walk_item(self, i);
}
/// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
fn with_trait_items<T>(
&mut self,
- trait_items: &'ast Vec<P<AssocItem>>,
+ trait_items: &'ast [P<AssocItem>],
f: impl FnOnce(&mut Self) -> T,
) -> T {
- let trait_assoc_items = replace(
- &mut self.diagnostic_metadata.current_trait_assoc_items,
- Some(&trait_items[..]),
- );
+ let trait_assoc_items =
+ replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items));
let result = f(self);
self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items;
result
}
// Record as bound if it's valid:
- let ident_valid = ident.name != kw::Invalid;
+ let ident_valid = ident.name != kw::Empty;
if ident_valid {
bindings.last_mut().unwrap().1.insert(ident);
}
for missing in &self.missing_named_lifetime_spots {
match missing {
MissingLifetimeSpot::Generics(generics) => {
- let (span, sugg) = if let Some(param) =
- generics.params.iter().find(|p| match p.kind {
- hir::GenericParamKind::Type {
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- ..
- } => false,
- hir::GenericParamKind::Lifetime {
- kind: hir::LifetimeParamKind::Elided,
- } => false,
- _ => true,
- }) {
+ let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
+ !matches!(p.kind, hir::GenericParamKind::Type {
+ synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+ ..
+ } | hir::GenericParamKind::Lifetime {
+ kind: hir::LifetimeParamKind::Elided,
+ })
+ }) {
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
} else {
suggests_in_band = true;
}
}
- /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics` so
- /// this function will emit an error if `min_const_generics` is enabled, the body identified by
+ /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
+ /// This function will emit an error if `const_generics` is not enabled, the body identified by
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
crate fn maybe_emit_forbidden_non_static_lifetime_error(
&self,
hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
);
- if self.tcx.features().min_const_generics && is_anon_const && !is_allowed_lifetime {
+ if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
feature_err(
&self.tcx.sess.parse_sess,
sym::const_generics,
let result = loop {
match *scope {
Scope::Body { id, s } => {
- // Non-static lifetimes are prohibited in anonymous constants under
- // `min_const_generics`.
+ // Non-static lifetimes are prohibited in anonymous constants without
+ // `const_generics`.
self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref);
outermost_body = Some(id);
) -> Resolver<'a> {
let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX };
let root_def_id = root_local_def_id.to_def_id();
- let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
+ let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
let graph_root = arenas.alloc_module(ModuleData {
no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude),
..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span)
});
- let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
+ let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
let empty_module = arenas.alloc_module(ModuleData {
no_implicit_prelude: true,
..ModuleData::new(
ribs: &[Rib<'a>],
) -> Option<LexicalScopeBinding<'a>> {
assert!(ns == TypeNS || ns == ValueNS);
- if ident.name == kw::Invalid {
+ if ident.name == kw::Empty {
return Some(LexicalScopeBinding::Res(Res::Err));
}
let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
{
// The macro is a proc macro derive
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
- if let Some(ext) = self.get_macro_by_def_id(def_id) {
- if !ext.is_builtin
- && ext.macro_kind() == MacroKind::Derive
- && parent.expansion.outer_expn_is_descendant_of(span.ctxt())
- {
- *poisoned = Some(node_id);
- return module.parent;
- }
+ let ext = self.get_macro_by_def_id(def_id);
+ if !ext.is_builtin
+ && ext.macro_kind() == MacroKind::Derive
+ && parent.expansion.outer_expn_is_descendant_of(span.ctxt())
+ {
+ *poisoned = Some(node_id);
+ return module.parent;
}
}
}
} else if i == 0 {
if ident
.name
- .with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase()))
+ .as_str()
+ .chars()
+ .next()
+ .map_or(false, |c| c.is_ascii_uppercase())
{
(format!("use of undeclared type `{}`", ident), None)
} else {
continue;
}
ConstantItemRibKind(trivial) => {
+ let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !trivial && self.session.features_untracked().min_const_generics {
+ if !(trivial
+ || features.const_generics
+ || features.lazy_normalization_consts)
+ {
// HACK(min_const_generics): If we encounter `Self` in an anonymous constant
// we can't easily tell if it's generic at this stage, so we instead remember
// this and then enforce the self type to be concrete later on.
continue;
}
ConstantItemRibKind(trivial) => {
+ let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !trivial && self.session.features_untracked().min_const_generics {
+ if !(trivial
+ || features.const_generics
+ || features.lazy_normalization_consts)
+ {
if record_used {
self.report_error(
span,
hygiene::update_dollar_crate_names(|ctxt| {
let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
match self.resolve_crate_root(ident).kind {
- ModuleKind::Def(.., name) if name != kw::Invalid => name,
+ ModuleKind::Def(.., name) if name != kw::Empty => name,
_ => kw::Crate,
}
});
for attr in attrs {
if let Some(val) = attr.doc_str() {
// FIXME: Should save-analysis beautify doc strings itself or leave it to users?
- result.push_str(&beautify_doc_string(val));
+ result.push_str(&beautify_doc_string(val).as_str());
result.push('\n');
} else if self.tcx.sess.check_name(attr, sym::doc) {
if let Some(meta_list) = attr.meta_item_list() {
#![feature(never_type)]
#![feature(nll)]
#![feature(associated_type_bounds)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
#![cfg_attr(test, feature(test))]
#![allow(rustc::internal)]
pub fn new(
sysroot: &'a Path,
triple: &'a str,
- search_paths: &'a Vec<SearchPath>,
+ search_paths: &'a [SearchPath],
tlib_path: &'a SearchPath,
kind: PathKind,
) -> FileSearch<'a> {
pub unstable_features: UnstableFeatures,
pub config: CrateConfig,
pub edition: Edition,
+ pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
/// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
pub raw_identifier_spans: Lock<Vec<Span>>,
/// Used to determine and report recursive module inclusions.
unstable_features: UnstableFeatures::from_environment(None),
config: FxHashSet::default(),
edition: ExpnId::root().expn_data().edition,
+ missing_fragment_specifiers: Default::default(),
raw_identifier_spans: Lock::new(Vec::new()),
included_mod_stack: Lock::new(vec![]),
source_map,
use rustc_macros::HashStable_Generic;
-/// The edition of the compiler (RFC 2052)
+/// The edition of the compiler. (See [RFC 2052](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md).)
#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, Decodable, Eq)]
#[derive(HashStable_Generic)]
pub enum Edition {
- // editions must be kept in order, oldest to newest
+ // When adding new editions, be sure to do the following:
+ //
+ // - update the `ALL_EDITIONS` const
+ // - update the `EDITION_NAME_LIST` const
+ // - add a `rust_####()` function to the session
+ // - update the enum in Cargo's sources as well
+ //
+ // Editions *must* be kept in order, oldest to newest.
/// The 2015 edition
Edition2015,
/// The 2018 edition
Edition2018,
- // when adding new editions, be sure to update:
- //
- // - Update the `ALL_EDITIONS` const
- // - Update the EDITION_NAME_LIST const
- // - add a `rust_####()` function to the session
- // - update the enum in Cargo's sources as well
}
-// must be in order from oldest to newest
+// Must be in order from oldest to newest.
pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
pub const EDITION_NAME_LIST: &str = "2015|2018";
parent: SyntaxContext::root(),
opaque: SyntaxContext::root(),
opaque_and_semitransparent: SyntaxContext::root(),
- dollar_crate_name: kw::Invalid,
+ dollar_crate_name: kw::Empty,
});
let mut ctxts = outer_ctxts.lock();
let new_len = raw_id as usize + 1;
ctxt_data,
);
// Make sure nothing weird happening while `decode_data` was running
- assert_eq!(dummy.dollar_crate_name, kw::Invalid);
+ assert_eq!(dummy.dollar_crate_name, kw::Empty);
});
Ok(new_ctxt)
+//! Levenshtein distances.
+//!
+//! The [Levenshtein distance] is a metric for measuring the difference between two strings.
+//!
+//! [Levenshtein distance]: https://en.wikipedia.org/wiki/Levenshtein_distance
+
use crate::symbol::Symbol;
use std::cmp;
#[cfg(test)]
mod tests;
-/// Finds the Levenshtein distance between two strings
+/// Finds the Levenshtein distance between two strings.
pub fn lev_distance(a: &str, b: &str) -> usize {
// cases which don't require further computation
if a.is_empty() {
dcol[t_last + 1]
}
-/// Finds the best match for a given word in the given iterator
+/// Finds the best match for a given word in the given iterator.
///
/// As a loose rule to avoid the obviously incorrect suggestions, it takes
/// an optional limit for the maximum allowable edit distance, which defaults
/// to one-third of the given word.
///
-/// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with
-/// a lower(upper)case letters mismatch.
+/// Besides Levenshtein, we use case insensitive comparison to improve accuracy
+/// on an edge case with a lower(upper)case letters mismatch.
#[cold]
pub fn find_best_match_for_name(
name_vec: &[Symbol],
fn sort_by_words(name: &str) -> String {
let mut split_words: Vec<&str> = name.split('_').collect();
- // We are sorting primitive &strs and can use unstable sort here
+ // We are sorting primitive &strs and can use unstable sort here.
split_words.sort_unstable();
split_words.join("_")
}
-//! The source positions and related helper functions.
+//! Source positions and related helper functions.
+//!
+//! Important concepts in this module include:
+//!
+//! - the *span*, represented by [`SpanData`] and related types;
+//! - source code as represented by a [`SourceMap`]; and
+//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module.
+//!
+//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata,
+//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`].
//!
//! ## Note
//!
impl RealFileName {
/// Returns the path suitable for reading from the file system on the local host.
- /// Avoid embedding this in build artifacts; see `stable_name` for that.
+ /// Avoid embedding this in build artifacts; see `stable_name()` for that.
pub fn local_path(&self) -> &Path {
match self {
RealFileName::Named(p)
}
/// Returns the path suitable for reading from the file system on the local host.
- /// Avoid embedding this in build artifacts; see `stable_name` for that.
+ /// Avoid embedding this in build artifacts; see `stable_name()` for that.
pub fn into_local_path(self) -> PathBuf {
match self {
RealFileName::Named(p)
/// Returns the path suitable for embedding into build artifacts. Note that
/// a virtualized path will not correspond to a valid file system path; see
- /// `local_path` for something that is more likely to return paths into the
+ /// `local_path()` for something that is more likely to return paths into the
/// local host file system.
pub fn stable_name(&self) -> &Path {
match self {
/// Custom sources for explicit parser calls from plugins and drivers.
Custom(String),
DocTest(PathBuf, isize),
- /// Post-substitution inline assembly from LLVM
+ /// Post-substitution inline assembly from LLVM.
InlineAsm(u64),
}
use FileName::*;
match *self {
Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()),
- // FIXME: might be nice to display both compoments of Devirtualized.
+ // FIXME: might be nice to display both components of Devirtualized.
// But for now (to backport fix for issue #70924), best to not
// perturb diagnostics so its obvious test suite still works.
Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => {
}
}
+/// Represents a span.
+///
/// Spans represent a region of code, used for error reporting. Positions in spans
-/// are *absolute* positions from the beginning of the source_map, not positions
-/// relative to `SourceFile`s. Methods on the `SourceMap` can be used to relate spans back
+/// are *absolute* positions from the beginning of the [`SourceMap`], not positions
+/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
/// to the original source.
-/// You must be careful if the span crosses more than one file - you will not be
+///
+/// You must be careful if the span crosses more than one file, since you will not be
/// able to use many of the functions on spans in source_map and you cannot assume
-/// that the length of the `span = hi - lo`; there may be space in the `BytePos`
-/// range between files.
+/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
+/// [`BytePos`] range between files.
///
/// `SpanData` is public because `Span` uses a thread-local interner and can't be
/// sent to other threads, but some pieces of performance infra run in a separate thread.
Span::new(lo, hi, SyntaxContext::root())
}
- /// Returns a new span representing an empty span at the beginning of this span
+ /// Returns a new span representing an empty span at the beginning of this span.
#[inline]
pub fn shrink_to_lo(self) -> Span {
let span = self.data();
}
#[inline]
- /// Returns true if hi == lo
+ /// Returns `true` if `hi == lo`.
pub fn is_empty(&self) -> bool {
let span = self.data();
span.hi == span.lo
}
/// Checks if a span is "internal" to a macro in which `unsafe`
- /// can be used without triggering the `unsafe_code` lint
+ /// can be used without triggering the `unsafe_code` lint.
// (that is, a macro marked with `#[allow_internal_unsafe]`).
pub fn allows_unsafe(&self) -> bool {
self.ctxt().outer_expn_data().allow_internal_unsafe
}
}
+/// A span together with some additional data.
#[derive(Clone, Debug)]
pub struct SpanLabel {
/// The span we are going to include in the final snippet.
/// any spans that are debug-printed during the closure's execution.
///
/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
-/// (see `rustc_interface::callbacks::span_debug1). However, some parts
+/// (see `rustc_interface::callbacks::span_debug1`). However, some parts
/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
/// a `TyCtxt` is available. In this case, we fall back to
/// the `SourceMap` provided to this function. If that is not available,
Unneeded,
Foreign {
kind: ExternalSourceKind,
- /// This SourceFile's byte-offset within the source_map of its original crate
+ /// This SourceFile's byte-offset within the source_map of its original crate.
original_start_pos: BytePos,
- /// The end of this SourceFile within the source_map of its original crate
+ /// The end of this SourceFile within the source_map of its original crate.
original_end_pos: BytePos,
},
}
}
}
-/// A single source in the `SourceMap`.
+/// A single source in the [`SourceMap`].
#[derive(Clone)]
pub struct SourceFile {
/// The name of the file that the source came from. Source that doesn't
/// Replaces `\r\n` with `\n` in-place in `src`.
///
-/// Returns error if there's a lone `\r` in the string
+/// Returns error if there's a lone `\r` in the string.
fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
if !src.as_bytes().contains(&b'\r') {
return;
}
impl_pos! {
- /// A byte offset. Keep this small (currently 32-bits), as AST contains
- /// a lot of them.
+ /// A byte offset.
+ ///
+ /// Keep this small (currently 32-bits), as AST contains a lot of them.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct BytePos(pub u32);
- /// A character offset. Because of multibyte UTF-8 characters, a byte offset
- /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
+ /// A character offset.
+ ///
+ /// Because of multibyte UTF-8 characters, a byte offset
+ /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
/// values to `CharPos` values as necessary.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct CharPos(pub usize);
}
/// Requirements for a `StableHashingContext` to be used in this crate.
-/// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in librustc_middle.
+///
+/// This is a hack to allow using the [`HashStable_Generic`] derive macro
+/// instead of implementing everything in rustc_middle.
pub trait HashStableContext {
fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
/// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
/// triple, which stays the same even if the containing `SourceFile` has moved
/// within the `SourceMap`.
+ ///
/// Also note that we are hashing byte offsets for the column, not unicode
/// codepoint offsets. For the purpose of the hash that's sufficient.
/// Also, hashing filenames is expensive so we avoid doing it twice when the
-//! The `SourceMap` tracks all the source code used within a single crate, mapping
+//! Types for tracking pieces of source code within a crate.
+//!
+//! The [`SourceMap`] tracks all the source code used within a single crate, mapping
//! from integer byte positions to the original source code location. Each bit
//! of source parsed during crate parsing (typically files, in-memory strings,
//! or various bits of macro expansion) cover a continuous range of bytes in the
-//! `SourceMap` and are represented by `SourceFile`s. Byte positions are stored in
-//! `Span` and used pervasively in the compiler. They are absolute positions
+//! `SourceMap` and are represented by [`SourceFile`]s. Byte positions are stored in
+//! [`Span`] and used pervasively in the compiler. They are absolute positions
//! within the `SourceMap`, which upon request can be converted to line and column
//! information, source code snippets, etc.
/// A compressed span.
///
-/// `SpanData` is 12 bytes, which is a bit too big to stick everywhere. `Span`
+/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
/// is a form that only takes up 8 bytes, with less space for the length and
/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
/// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base`
/// values never cause interning. The number of bits needed for `base`
/// depends on the crate size. 32 bits allows up to 4 GiB of code in a crate.
-/// `script-servo` is the largest crate in `rustc-perf`, requiring 26 bits
-/// for some spans.
/// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits
/// in `SpanData`, which means that large `len` values will cause interning.
/// The number of bits needed for `len` does not depend on the crate size.
-/// The most common number of bits for `len` are 0--7, with a peak usually at
-/// 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
+/// The most common numbers of bits for `len` are from 0 to 7, with a peak usually
+/// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
/// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
/// dozens of times in a typical crate.
/// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
use std::hash::{Hash, Hasher};
use std::str;
-use crate::{Span, DUMMY_SP, SESSION_GLOBALS};
+use crate::{Edition, Span, DUMMY_SP, SESSION_GLOBALS};
#[cfg(test)]
mod tests;
Keywords {
// Special reserved identifiers used internally for elided lifetimes,
// unnamed method parameters, crate root module, error recovery etc.
- Invalid: "",
+ Empty: "",
PathRoot: "{{root}}",
DollarCrate: "$crate",
Underscore: "_",
#[inline]
pub fn invalid() -> Ident {
- Ident::with_dummy_span(kw::Invalid)
+ Ident::with_dummy_span(kw::Empty)
}
/// Maps a string to an identifier with a dummy span.
with_interner(|interner| interner.intern(string))
}
- /// Access the symbol's chars. This is a slowish operation because it
- /// requires locking the symbol interner.
- pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
- with_interner(|interner| f(interner.get(self)))
- }
-
/// Convert to a `SymbolStr`. This is a slowish operation because it
/// requires locking the symbol interner.
pub fn as_str(self) -> SymbolStr {
}
pub fn is_empty(self) -> bool {
- self == kw::Invalid
+ self == kw::Empty
}
/// This method is supposed to be used in error messages, so it's expected to be
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.with(|str| fmt::Debug::fmt(&str, f))
+ fmt::Debug::fmt(&self.as_str(), f)
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.with(|str| fmt::Display::fmt(&str, f))
+ fmt::Display::fmt(&self.as_str(), f)
}
}
impl<S: Encoder> Encodable<S> for Symbol {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- self.with(|string| s.emit_str(string))
+ s.emit_str(&self.as_str())
}
}
}
impl Symbol {
- fn is_used_keyword_2018(self) -> bool {
- self >= kw::Async && self <= kw::Dyn
+ fn is_special(self) -> bool {
+ self <= kw::Underscore
+ }
+
+ fn is_used_keyword_always(self) -> bool {
+ self >= kw::As && self <= kw::While
+ }
+
+ fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
+ (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018
+ }
+
+ fn is_unused_keyword_always(self) -> bool {
+ self >= kw::Abstract && self <= kw::Yield
}
- fn is_unused_keyword_2018(self) -> bool {
- self == kw::Try
+ fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
+ self == kw::Try && edition() >= Edition::Edition2018
+ }
+
+ pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
+ self.is_special()
+ || self.is_used_keyword_always()
+ || self.is_unused_keyword_always()
+ || self.is_used_keyword_conditional(edition)
+ || self.is_unused_keyword_conditional(edition)
}
/// A keyword or reserved identifier that can be used as a path segment.
/// Returns `true` if this symbol can be a raw identifier.
pub fn can_be_raw(self) -> bool {
- self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword()
+ self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword()
}
}
// Returns `true` for reserved identifiers used internally for elided lifetimes,
// unnamed method parameters, crate root module, error recovery etc.
pub fn is_special(self) -> bool {
- self.name <= kw::Underscore
+ self.name.is_special()
}
/// Returns `true` if the token is a keyword used in the language.
pub fn is_used_keyword(self) -> bool {
// Note: `span.edition()` is relatively expensive, don't call it unless necessary.
- self.name >= kw::As && self.name <= kw::While
- || self.name.is_used_keyword_2018() && self.span.rust_2018()
+ self.name.is_used_keyword_always()
+ || self.name.is_used_keyword_conditional(|| self.span.edition())
}
/// Returns `true` if the token is a keyword reserved for possible future use.
pub fn is_unused_keyword(self) -> bool {
// Note: `span.edition()` is relatively expensive, don't call it unless necessary.
- self.name >= kw::Abstract && self.name <= kw::Yield
- || self.name.is_unused_keyword_2018() && self.span.rust_2018()
+ self.name.is_unused_keyword_always()
+ || self.name.is_unused_keyword_conditional(|| self.span.edition())
}
/// Returns `true` if the token is either a special identifier or a keyword.
pub fn is_reserved(self) -> bool {
- self.is_special() || self.is_used_keyword() || self.is_unused_keyword()
+ // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
+ self.name.is_reserved(|| self.span.edition())
}
/// A keyword or reserved identifier that can be used as a path segment.
SESSION_GLOBALS.with(|session_globals| f(&mut *session_globals.symbol_interner.lock()))
}
-/// An alternative to `Symbol`, useful when the chars within the symbol need to
+/// An alternative to [`Symbol`], useful when the chars within the symbol need to
/// be accessed. It deliberately has limited functionality and should only be
/// used for temporary values.
///
/// 'b` (and hence, transitively, that `T: 'a`). This method would
/// add those assumptions into the outlives-environment.
///
- /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
+ /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
fn add_implied_bounds(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
#[allow(dead_code)]
impl<A> AutoTraitResult<A> {
fn is_auto(&self) -> bool {
- match *self {
- AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
- _ => false,
- }
+ matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
}
}
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
- match *p.ty().skip_binder().kind() {
- ty::Projection(proj) if proj == p.skip_binder().projection_ty => true,
- _ => false,
- }
+ matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
}
fn evaluate_nested_obligations(
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
- let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) {
- Some(true) => true,
- _ => false,
- };
+ let involves_placeholder =
+ matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
}
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
let arg_length = arguments.len();
- let distinct = match &other[..] {
- &[ArgKind::Tuple(..)] => true,
- _ => false,
- };
+ let distinct = matches!(other, &[ArgKind::Tuple(..)]);
match (arg_length, arguments.get(0)) {
(1, Some(&ArgKind::Tuple(_, ref fields))) => {
format!("a single {}-tuple as argument", fields.len())
normalized_ty, data.ty
);
- let is_normalized_ty_expected = match &obligation.cause.code {
- ObligationCauseCode::ItemObligation(_)
+ let is_normalized_ty_expected = !matches!(obligation.cause.code, ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
- | ObligationCauseCode::ObjectCastObligation(_) => false,
- _ => true,
- };
+ | ObligationCauseCode::ObjectCastObligation(_));
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected,
// This works fairly well because trait matching does not actually care about param-env
// TypeOutlives predicates - these are normally used by regionck.
let outlives_predicates: Vec<_> = predicates
- .drain_filter(|predicate| match predicate.skip_binders() {
- ty::PredicateAtom::TypeOutlives(..) => true,
- _ => false,
+ .drain_filter(|predicate| {
+ matches!(predicate.skip_binders(), ty::PredicateAtom::TypeOutlives(..))
})
.collect();
return Ok(None);
}
Err(ProjectionCacheEntry::InProgress) => {
- // If while normalized A::B, we are asked to normalize
- // A::B, just return A::B itself. This is a conservative
- // answer, in the sense that A::B *is* clearly equivalent
- // to A::B, though there may be a better value we can
- // find.
-
// Under lazy normalization, this can arise when
// bootstrapping. That is, imagine an environment with a
// where-clause like `A::B == u32`. Now, if we are asked
debug!("found cache entry: in-progress");
+ // Cache that normalizing this projection resulted in a cycle. This
+ // should ensure that, unless this happens within a snapshot that's
+ // rolled back, fulfillment or evaluation will notice the cycle.
+
+ infcx.inner.borrow_mut().projection_cache().recur(cache_key);
+ return Err(InProgress);
+ }
+ Err(ProjectionCacheEntry::Recur) => {
return Err(InProgress);
}
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) {
debug!("project: overflow!");
- return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
+ match selcx.query_mode() {
+ super::TraitQueryMode::Standard => {
+ selcx.infcx().report_overflow_error(&obligation, true);
+ }
+ super::TraitQueryMode::Canonical => {
+ return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
+ }
+ }
}
let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?;
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
// Other bounds. Consider both in-scope bounds from fn decl
// and applicable impls. There is a certain set of precedence rules here.
// User-defined copy impls are permitted, but only for
// structs and enums.
- self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
// For other types, we'll use the builtin rules.
let copy_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
// `DiscriminantKind` is automatically implemented for every type.
candidates.vec.push(DiscriminantKindCandidate);
// Sized is never implementable by end-users, it is
// always automatically computed.
let sized_conditions = self.sized_conditions(obligation);
- self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?;
+ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
} else if lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else {
// for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
// types have builtin support for `Clone`.
let clone_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
+ self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
}
- self.assemble_generator_candidates(obligation, &mut candidates)?;
- self.assemble_closure_candidates(obligation, &mut candidates)?;
- self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
- self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+ self.assemble_generator_candidates(obligation, &mut candidates);
+ self.assemble_closure_candidates(obligation, &mut candidates);
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
}
// Auto implementations have lower priority, so we only
// consider triggering a default if there is no other impl that can apply.
if candidates.vec.is_empty() {
- self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?;
+ self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
}
debug!("candidate list size: {}", candidates.vec.len());
Ok(candidates)
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
- return Ok(());
+ return;
}
// Okay to skip binder because the substs on generator types never
}
_ => {}
}
-
- Ok(())
}
/// Checks for the artificial impl that the compiler will create for an obligation like `X :
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) {
Some(k) => k,
None => {
- return Ok(());
+ return;
}
};
}
_ => {}
}
-
- Ok(())
}
/// Implements one of the `Fn()` family for a fn pointer.
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
// We provide impl of all fn traits for fn pointers.
if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() {
- return Ok(());
+ return;
}
// Okay to skip binder because what we are inspecting doesn't involve bound regions.
}
_ => {}
}
-
- Ok(())
}
/// Searches for impls that might apply to `obligation`.
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
debug!(?obligation, "assemble_candidates_from_impls");
// Essentially any user-written impl will match with an error type,
// Since compilation is already guaranteed to fail, this is just
// to try to show the 'nicest' possible errors to the user.
if obligation.references_error() {
- return Ok(());
+ return;
}
self.tcx().for_each_relevant_impl(
});
},
);
-
- Ok(())
}
fn assemble_candidates_from_auto_impls(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
// Okay to skip binder here because the tests we do below do not involve bound regions.
let self_ty = obligation.self_ty().skip_binder();
debug!(?self_ty, "assemble_candidates_from_auto_impls");
// where-clause or, in the case of an object type,
// it could be that the object type lists the
// trait (e.g., `Foo+Send : Send`). See
- // `compile-fail/typeck-default-trait-impl-send-param.rs`
+ // `ui/typeck/typeck-default-trait-impl-send-param.rs`
// for an example of a test case that exercises
// this path.
}
_ => candidates.vec.push(AutoImplCandidate(def_id)),
}
}
-
- Ok(())
}
/// Searches for impls that might apply to `obligation`.
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
// Okay to skip binder here because the tests we do below do not involve bound regions.
let self_ty = obligation.self_ty().skip_binder();
debug!(?self_ty, "assemble_candidates_for_trait_alias");
if self.tcx().is_trait_alias(def_id) {
candidates.vec.push(TraitAliasCandidate(def_id));
}
-
- Ok(())
}
/// Assembles the trait which are built-in to the language itself:
&mut self,
conditions: BuiltinImplConditions<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
match conditions {
BuiltinImplConditions::Where(nested) => {
debug!(?nested, "builtin_bound");
candidates.ambiguous = true;
}
}
-
- Ok(())
}
}
self.infcx.tcx
}
+ pub(super) fn query_mode(&self) -> TraitQueryMode {
+ self.query_mode
+ }
+
///////////////////////////////////////////////////////////////////////////
// Selection
//
let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
let db = ChalkRustIrDatabase { interner, reempty_placeholder };
let solution = solver.solve(&db, &lowered_goal);
- debug!(?obligation, ?solution, "evaluatate goal");
+ debug!(?obligation, ?solution, "evaluate goal");
// Ideally, the code to convert *back* to rustc types would live close to
// the code to convert *from* rustc types. Right now though, we don't
generics: &ty::Generics,
) -> bool {
let explicit = !seg.infer_args;
- let impl_trait =
- generics.params.iter().any(|param| match param.kind {
- ty::GenericParamDefKind::Type {
- synthetic:
- Some(
- hir::SyntheticTyParamKind::ImplTrait
- | hir::SyntheticTyParamKind::FromAttr,
- ),
- ..
- } => true,
- _ => false,
- });
+ let impl_trait = generics.params.iter().any(|param| {
+ matches!(param.kind, ty::GenericParamDefKind::Type {
+ synthetic:
+ Some(
+ hir::SyntheticTyParamKind::ImplTrait
+ | hir::SyntheticTyParamKind::FromAttr,
+ ),
+ ..
+ })
+ });
if explicit && impl_trait {
let spans = seg
if let Some(ty) = prohibit_opaque.break_value() {
let is_async = match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
- hir::OpaqueTyOrigin::AsyncFn => true,
- _ => false,
- },
+ ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
+ matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
+ }
_ => unreachable!(),
};
}
if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
- let is_unit = |var: &hir::Variant<'_>| match var.data {
- hir::VariantData::Unit(..) => true,
- _ => false,
- };
+ let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
let has_non_units = vs.iter().any(|var| !is_unit(var));
false
}
- fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option<String> {
- s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
- }
-
/// This function is used to determine potential "simple" improvements or users' errors and
/// provide them useful help. For example:
///
return None;
}
+ let replace_prefix = |s: &str, old: &str, new: &str| {
+ s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
+ };
+
let is_struct_pat_shorthand_field =
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
(&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(src) = self.replace_prefix(&src, "b\"", "\"") {
+ if let Some(src) = replace_prefix(&src, "b\"", "\"") {
return Some((
sp,
"consider removing the leading `b`",
(&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(src) = self.replace_prefix(&src, "\"", "b\"") {
+ if let Some(src) = replace_prefix(&src, "\"", "b\"") {
return Some((
sp,
"consider adding a leading `b`",
hir::Mutability::Mut => {
let new_prefix = "&mut ".to_owned() + derefs;
match mutbl_a {
- hir::Mutability::Mut => self
- .replace_prefix(&src, "&mut ", &new_prefix)
- .map(|s| (s, Applicability::MachineApplicable)),
- hir::Mutability::Not => self
- .replace_prefix(&src, "&", &new_prefix)
- .map(|s| (s, Applicability::Unspecified)),
+ hir::Mutability::Mut => {
+ replace_prefix(&src, "&mut ", &new_prefix)
+ .map(|s| (s, Applicability::MachineApplicable))
+ }
+ hir::Mutability::Not => {
+ replace_prefix(&src, "&", &new_prefix)
+ .map(|s| (s, Applicability::Unspecified))
+ }
}
}
hir::Mutability::Not => {
let new_prefix = "&".to_owned() + derefs;
match mutbl_a {
- hir::Mutability::Mut => self
- .replace_prefix(&src, "&mut ", &new_prefix)
- .map(|s| (s, Applicability::MachineApplicable)),
- hir::Mutability::Not => self
- .replace_prefix(&src, "&", &new_prefix)
- .map(|s| (s, Applicability::MachineApplicable)),
+ hir::Mutability::Mut => {
+ replace_prefix(&src, "&mut ", &new_prefix)
+ .map(|s| (s, Applicability::MachineApplicable))
+ }
+ hir::Mutability::Not => {
+ replace_prefix(&src, "&", &new_prefix)
+ .map(|s| (s, Applicability::MachineApplicable))
+ }
}
}
} {
ty: Ty<'tcx>,
span: Span,
body_id: hir::HirId,
-) -> Result<(), ErrorReported> {
+) {
debug!("check_drop_obligations typ: {:?}", ty);
let cause = &ObligationCause::misc(span, body_id);
let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty);
debug!("dropck_outlives = {:#?}", infer_ok);
rcx.fcx.register_infer_ok_obligations(infer_ok);
-
- Ok(())
}
// This is an implementation of the TypeRelation trait with the
Ok(method)
}
Err(error) => {
- if segment.ident.name != kw::Invalid {
+ if segment.ident.name != kw::Empty {
self.report_extended_method_error(segment, span, args, rcvr_t, error);
}
Err(())
return field_ty;
}
- if field.name == kw::Invalid {
+ if field.name == kw::Empty {
} else if self.method_exists(field, expr_t, expr.hir_id, true) {
self.ban_take_value_of_method(expr, expr_t, field);
} else if !expr_t.is_primitive_ty() {
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
_ => Err(ErrorReported),
};
- if item_name.name != kw::Invalid {
+ if item_name.name != kw::Empty {
if let Some(mut e) = self.report_method_error(
span,
ty,
self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
}
- let is_closure = match arg.kind {
- ExprKind::Closure(..) => true,
- _ => false,
- };
+ let is_closure = matches!(arg.kind, ExprKind::Closure(..));
if is_closure != check_closures {
continue;
| sym::rustc_peek
| sym::maxnumf64
| sym::type_name
+ | sym::forget
| sym::variant_count => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
probe_cx.assemble_inherent_candidates();
match scope {
ProbeScope::TraitsInScope => {
- probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?
+ probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)
}
- ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits()?,
+ ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
};
op(probe_cx)
})
}
}
- fn assemble_extension_candidates_for_traits_in_scope(
- &mut self,
- expr_hir_id: hir::HirId,
- ) -> Result<(), MethodError<'tcx>> {
+ fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_hir_id: hir::HirId) {
let mut duplicates = FxHashSet::default();
let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id);
if let Some(applicable_traits) = opt_applicable_traits {
for trait_candidate in applicable_traits.iter() {
let trait_did = trait_candidate.def_id;
if duplicates.insert(trait_did) {
- let result = self.assemble_extension_candidates_for_trait(
+ self.assemble_extension_candidates_for_trait(
&trait_candidate.import_ids,
trait_did,
);
- result?;
}
}
}
- Ok(())
}
- fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
+ fn assemble_extension_candidates_for_all_traits(&mut self) {
let mut duplicates = FxHashSet::default();
for trait_info in suggest::all_traits(self.tcx) {
if duplicates.insert(trait_info.def_id) {
- self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id)?;
+ self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id);
}
}
- Ok(())
}
pub fn matches_return_type(
&mut self,
import_ids: &SmallVec<[LocalDefId; 1]>,
trait_def_id: DefId,
- ) -> Result<(), MethodError<'tcx>> {
+ ) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
let trait_substs = self.fresh_item_substs(trait_def_id);
let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
);
}
}
- Ok(())
}
fn candidate_method_names(&self) -> Vec<Ident> {
let span = self.span;
let tcx = self.tcx;
- self.assemble_extension_candidates_for_all_traits()?;
+ self.assemble_extension_candidates_for_all_traits();
let out_of_scope_traits = match self.pick_core() {
Some(Ok(p)) => vec![p.item.container.id()],
pat.each_binding(|_, hir_id, span, _| {
let typ = self.resolve_node_type(hir_id);
let body_id = self.body_id;
- let _ = dropck::check_drop_obligations(self, typ, span, body_id);
+ dropck::check_drop_obligations(self, typ, span, body_id);
})
}
}
hir_id: hir::HirId,
) {
assert!(
- match fk {
- intravisit::FnKind::Closure(..) => true,
- _ => false,
- },
+ matches!(fk, intravisit::FnKind::Closure(..)),
"visit_fn invoked for something other than a closure"
);
if place_with_id.place.projections.is_empty() {
let typ = self.resolve_type(place_with_id.place.ty());
let body_id = self.body_id;
- let _ = dropck::check_drop_obligations(self, typ, span, body_id);
+ dropck::check_drop_obligations(self, typ, span, body_id);
}
}
}
let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
None => {
- let min_cap_list = vec![ty::CapturedPlace { place: place, info: capture_info }];
+ let min_cap_list = vec![ty::CapturedPlace { place, info: capture_info }];
root_var_min_capture_list.insert(var_hir_id, min_cap_list);
continue;
}
let err_ty_str;
let mut is_ptr = true;
- let err = if tcx.features().min_const_generics {
+ let err = if tcx.features().const_generics {
+ match ty.peel_refs().kind() {
+ ty::FnPtr(_) => Some("function pointers"),
+ ty::RawPtr(_) => Some("raw pointers"),
+ _ => None,
+ }
+ } else {
match ty.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
ty::FnPtr(_) => Some("function pointers"),
Some(err_ty_str.as_str())
}
}
- } else {
- match ty.peel_refs().kind() {
- ty::FnPtr(_) => Some("function pointers"),
- ty::RawPtr(_) => Some("raw pointers"),
- _ => None,
- }
};
if let Some(unsupported_type) = err {
if is_ptr {
if let Some(span) = span {
sugg.push((span, format!("<{}>", type_name)));
}
- } else if let Some(arg) = generics.iter().find(|arg| match arg.name {
- hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
- _ => false,
- }) {
+ } else if let Some(arg) = generics
+ .iter()
+ .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. })))
+ {
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
sugg.push((arg.span, (*type_name).to_string()));
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
- // `feature(min_const_generics)`.
+ // `min_const_generics`.
Some(parent_def_id.to_def_id())
} else {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
generics.parent_count + generics.params.len()
});
- let mut params: Vec<_> = opt_self.into_iter().collect();
+ let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
+
+ if let Some(opt_self) = opt_self {
+ params.push(opt_self);
+ }
let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
let mut diag = bad_placeholder_type(tcx, visitor.0);
let ret_ty = fn_sig.output();
if ret_ty != tcx.ty_error() {
- diag.span_suggestion(
- ty.span,
- "replace with the correct return type",
- ret_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
+ if !ret_ty.is_closure() {
+ let ret_ty_str = match ret_ty.kind() {
+ // Suggest a function pointer return type instead of a unique function definition
+ // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
+ // syntax)
+ ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
+ _ => ret_ty.to_string(),
+ };
+ diag.span_suggestion(
+ ty.span,
+ "replace with the correct return type",
+ ret_ty_str,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
+ // to prevent the user from getting a papercut while trying to use the unique closure
+ // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
+ diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
+ diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+ }
}
diag.emit();
ty::Binder::bind(fn_sig)
const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
// We use an `IndexSet` to preserves order of insertion.
- // Preserving the order of insertion is important here so as not to break
- // compile-fail UI tests.
+ // Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
let ast_generics = match node {
let upvars = self.tcx().upvars_mentioned(self.body_owner);
// For purposes of this function, generator and closures are equivalent.
- let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() {
- ty::Closure(..) | ty::Generator(..) => true,
- _ => false,
- };
+ let body_owner_is_closure = matches!(
+ self.tcx().type_of(self.body_owner.to_def_id()).kind(),
+ ty::Closure(..) | ty::Generator(..)
+ );
if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
{
kind: ProjectionKind,
) -> PlaceWithHirId<'tcx> {
let mut projections = base_place.place.projections;
- projections.push(Projection { kind: kind, ty: ty });
+ projections.push(Projection { kind, ty });
let ret = PlaceWithHirId::new(
node.hir_id(),
base_place.place.base_ty,
# Whether to allow failures when building tools
#missing-tools = false
+
+# List of compression formats to use when generating dist tarballs. The list of
+# formats is provided to rust-installer, which must support all of them.
+#compression-formats = ["gz", "xz"]
///
/// assert_eq!(heap.len(), 2);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.data.len()
/// Pushes all key-value pairs to the end of the tree, incrementing a
/// `length` variable along the way. The latter makes it easier for the
/// caller to avoid a leak when the iterator panicks.
- fn bulk_push<I>(&mut self, iter: I, length: &mut usize)
+ pub fn bulk_push<I>(&mut self, iter: I, length: &mut usize)
where
I: Iterator<Item = (K, V)>,
{
// the appended elements even if advancing the iterator panicks.
*length += 1;
}
- self.fix_right_edge();
+ self.fix_right_border_of_plentiful();
}
- fn fix_right_edge(&mut self) {
- // Handle underfull nodes, start from the top.
+ /// Stock up any underfull nodes on the right border of the tree.
+ /// The other nodes, those that are not the root nor a rightmost edge,
+ /// must have MIN_LEN elements to spare.
+ fn fix_right_border_of_plentiful(&mut self) {
let mut cur_node = self.borrow_mut();
while let Internal(internal) = cur_node.force() {
// Check if right-most child is underfull.
let mut last_kv = internal.last_kv().consider_for_balancing();
+ debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2);
let right_child_len = last_kv.right_child_len();
if right_child_len < MIN_LEN {
// We need to steal.
let (map, dormant_map) = DormantMutRef::new(self);
let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut();
match search::search_tree::<marker::Mut<'_>, K, (), K>(root_node, &key) {
- Found(handle) => Some(mem::replace(handle.into_key_mut(), key)),
+ Found(mut kv) => Some(mem::replace(kv.key_mut(), key)),
GoDown(handle) => {
VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(());
None
/// a.insert(1, "a");
/// assert_eq!(a.len(), 1);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn len(&self) -> usize {
}
}
}
+
+ // Transform the tree to minimize wasted space, obtaining fewer nodes that
+ // are mostly filled up to their capacity. The same compact tree could have
+ // been obtained by inserting keys in a shrewd order.
+ fn compact(&mut self)
+ where
+ K: Ord,
+ {
+ let iter = mem::take(self).into_iter();
+ let root = BTreeMap::ensure_is_owned(&mut self.root);
+ root.bulk_push(iter, &mut self.length);
+ }
}
impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
fn assert_min_len(self, min_len: usize) {
- assert!(self.len() >= min_len, "{} < {}", self.len(), min_len);
+ assert!(self.len() >= min_len, "node len {} < {}", self.len(), min_len);
if let node::ForceResult::Internal(node) = self.force() {
for idx in 0..=node.len() {
let edge = unsafe { Handle::new_edge(node, idx) };
}
#[test]
-fn test_insert_into_full_left() {
- let mut map: BTreeMap<_, _> = (0..NODE_CAPACITY).map(|i| (i * 2, ())).collect();
- assert!(map.insert(NODE_CAPACITY, ()).is_none());
- map.check();
+fn test_insert_into_full_height_0() {
+ let size = NODE_CAPACITY;
+ for pos in 0..=size {
+ let mut map: BTreeMap<_, _> = (0..size).map(|i| (i * 2 + 1, ())).collect();
+ assert!(map.insert(pos * 2, ()).is_none());
+ map.check();
+ }
}
#[test]
-fn test_insert_into_full_right() {
- let mut map: BTreeMap<_, _> = (0..NODE_CAPACITY).map(|i| (i * 2, ())).collect();
- assert!(map.insert(NODE_CAPACITY + 2, ()).is_none());
- map.check();
+fn test_insert_into_full_height_1() {
+ let size = NODE_CAPACITY + 1 + NODE_CAPACITY;
+ for pos in 0..=size {
+ let mut map: BTreeMap<_, _> = (0..size).map(|i| (i * 2 + 1, ())).collect();
+ map.compact();
+ let root_node = map.root.as_ref().unwrap().reborrow();
+ assert_eq!(root_node.len(), 1);
+ assert_eq!(root_node.first_leaf_edge().into_node().len(), NODE_CAPACITY);
+ assert_eq!(root_node.last_leaf_edge().into_node().len(), NODE_CAPACITY);
+
+ assert!(map.insert(pos * 2, ()).is_none());
+ map.check();
+ }
}
macro_rules! create_append_test {
}
fn rand_data(len: usize) -> Vec<(u32, u32)> {
- assert!(len * 2 <= 70029); // from that point on numbers repeat
let mut rng = DeterministicRng::new();
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))
}
assert_eq!(*right.last_key_value().unwrap().0, last);
}
+#[test]
+fn test_split_off_halfway() {
+ let mut rng = DeterministicRng::new();
+ for &len in &[NODE_CAPACITY, 25, 50, 75, 100] {
+ let mut data = Vec::from_iter((0..len).map(|_| (rng.next(), ())));
+ // Insertion in non-ascending order creates some variation in node length.
+ let mut map = BTreeMap::from_iter(data.iter().copied());
+ data.sort();
+ let small_keys = data.iter().take(len / 2).map(|kv| kv.0);
+ let large_keys = data.iter().skip(len / 2).map(|kv| kv.0);
+ let split_key = large_keys.clone().next().unwrap();
+ let right = map.split_off(&split_key);
+ map.check();
+ right.check();
+ assert!(map.keys().copied().eq(small_keys));
+ assert!(right.keys().copied().eq(large_keys));
+ }
+}
+
#[test]
fn test_split_off_large_random_sorted() {
// Miri is too slow
#[cfg(test)]
/// XorShiftRng
struct DeterministicRng {
+ count: usize,
x: u32,
y: u32,
z: u32,
#[cfg(test)]
impl DeterministicRng {
fn new() -> Self {
- DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
+ DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
}
- /// Guarantees that the first 70029 results are unique.
+ /// Guarantees that each returned number is unique.
fn next(&mut self) -> u32 {
+ self.count += 1;
+ assert!(self.count <= 70029);
let x = self.x;
let t = x ^ (x << 11);
self.x = self.y;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ptr::{self, NonNull};
+use core::slice::SliceIndex;
use crate::alloc::{Allocator, Global, Layout};
use crate::boxed::Box;
/// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`.
/// Therefore, we have to explicitly call `reborrow` on a more powerfull
/// `NodeRef` in order to reach a method like `key_at`.
-/// - All methods on `NodeRef` that return some kind of reference, except
-/// `reborrow` and `reborrow_mut`, take `self` by value and not by reference.
-/// This avoids silently returning a second reference somewhere in the tree.
-/// That is irrelevant when `BorrowType` is `Immut<'a>`, but the rule does
-/// no harm because we make those `NodeRef` implicitly `Copy`.
-/// The rule also avoids implicitly returning the lifetime of `&self`,
-/// instead of the lifetime carried by `BorrowType`.
-/// An exception to this rule are the insert functions.
-/// - Given the above, we need a `reborrow_mut` to explicitly copy a `Mut<'a>`
-/// `NodeRef` whenever we want to invoke a method returning an extra reference
-/// somewhere in the tree.
+///
+/// All methods on `NodeRef` that return some kind of reference, either:
+/// - Take `self` by value, and return the lifetime carried by `BorrowType`.
+/// Sometimes, to invoke such a method, we need to call `reborrow_mut`.
+/// - Take `self` by reference, and (implicitly) return that reference's
+/// lifetime, instead of the lifetime carried by `BorrowType`. That way,
+/// the borrow checker guarantees that the `NodeRef` remains borrowed as long
+/// as the returned reference is used.
+/// The methods supporting insert bend this rule by returning a raw pointer,
+/// i.e., a reference without any lifetime.
pub struct NodeRef<BorrowType, K, V, Type> {
/// The number of levels that the node and the level of leaves are apart, a
/// constant of the node that cannot be entirely described by `Type`, and that
}
}
-impl<'a, K, V> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
- /// Exposes the data of an internal node in an immutable tree.
- fn as_internal(this: &Self) -> &'a InternalNode<K, V> {
- let ptr = Self::as_internal_ptr(this);
- // SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
- unsafe { &*ptr }
- }
-}
-
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
- /// Offers exclusive access to the data of an internal node.
- fn as_internal_mut(this: &mut Self) -> &'a mut InternalNode<K, V> {
- let ptr = Self::as_internal_ptr(this);
+ /// Borrows exclusive access to the data of an internal node.
+ fn as_internal_mut(&mut self) -> &mut InternalNode<K, V> {
+ let ptr = Self::as_internal_ptr(self);
unsafe { &mut *ptr }
}
}
/// The node has more than `idx` initialized elements.
pub unsafe fn key_at(self, idx: usize) -> &'a K {
debug_assert!(idx < self.len());
- unsafe { Self::as_leaf(&self).keys.get_unchecked(idx).assume_init_ref() }
+ unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() }
}
/// Exposes one of the values stored in the node.
/// The node has more than `idx` initialized elements.
unsafe fn val_at(self, idx: usize) -> &'a V {
debug_assert!(idx < self.len());
- unsafe { Self::as_leaf(&self).vals.get_unchecked(idx).assume_init_ref() }
- }
-}
-
-impl<'a, K, V> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
- /// Exposes the contents of one of the edges in the node.
- ///
- /// # Safety
- /// The node has more than `idx` initialized elements.
- unsafe fn edge_at(self, idx: usize) -> &'a BoxedNode<K, V> {
- debug_assert!(idx <= self.len());
- unsafe { Self::as_internal(&self).edges.get_unchecked(idx).assume_init_ref() }
+ unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() }
}
}
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
/// Exposes the leaf portion of any leaf or internal node in an immutable tree.
- fn as_leaf(this: &Self) -> &'a LeafNode<K, V> {
- let ptr = Self::as_leaf_ptr(this);
+ fn into_leaf(self) -> &'a LeafNode<K, V> {
+ let ptr = Self::as_leaf_ptr(&self);
// SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
unsafe { &*ptr }
}
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
- /// Offers exclusive access to the leaf portion of any leaf or internal node.
- fn as_leaf_mut(this: &mut Self) -> &'a mut LeafNode<K, V> {
- let ptr = Self::as_leaf_ptr(this);
+ /// Borrows exclusive access to the leaf portion of any leaf or internal node.
+ fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
+ let ptr = Self::as_leaf_ptr(self);
// SAFETY: we have exclusive access to the entire node.
unsafe { &mut *ptr }
}
-}
-impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
- /// Offers exclusive access to a part of the key storage area.
- ///
- /// # Safety
- /// The node has more than `idx` initialized elements.
- unsafe fn into_key_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<K> {
- debug_assert!(idx < self.len());
- unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(idx) }
- }
-
- /// Offers exclusive access to a part of the value storage area.
- ///
- /// # Safety
- /// The node has more than `idx` initialized elements.
- unsafe fn into_val_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<V> {
- debug_assert!(idx < self.len());
- unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(idx) }
+ /// Offers exclusive access to the leaf portion of any leaf or internal node.
+ fn into_leaf_mut(mut self) -> &'a mut LeafNode<K, V> {
+ let ptr = Self::as_leaf_ptr(&mut self);
+ // SAFETY: we have exclusive access to the entire node.
+ unsafe { &mut *ptr }
}
}
-impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
- /// Offers exclusive access to a part of the storage area for edge contents.
+impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
+ /// Borrows exclusive access to an element of the key storage area.
///
/// # Safety
- /// The node has at least `idx` initialized elements.
- unsafe fn into_edge_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<BoxedNode<K, V>> {
- debug_assert!(idx <= self.len());
- unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(idx) }
- }
-}
-
-impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
- /// Exposes the entire key storage area in the node,
- /// regardless of the node's current length,
- /// having exclusive access to the entire node.
- unsafe fn key_area(self) -> &'a [MaybeUninit<K>] {
- Self::as_leaf(&self).keys.as_slice()
- }
-
- /// Exposes the entire value storage area in the node,
- /// regardless of the node's current length,
- /// having exclusive access to the entire node.
- unsafe fn val_area(self) -> &'a [MaybeUninit<V>] {
- Self::as_leaf(&self).vals.as_slice()
- }
-}
-
-impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
- /// Exposes the entire storage area for edge contents in the node,
- /// regardless of the node's current length,
- /// having exclusive access to the entire node.
- unsafe fn edge_area(self) -> &'a [MaybeUninit<BoxedNode<K, V>>] {
- Self::as_internal(&self).edges.as_slice()
- }
-}
-
-impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
- /// Offers exclusive access to a sized slice of key storage area in the node.
- unsafe fn into_key_area_slice(mut self) -> &'a mut [MaybeUninit<K>] {
- let len = self.len();
+ /// `index` is in bounds of 0..CAPACITY
+ unsafe fn key_area_mut<I, Output: ?Sized>(&mut self, index: I) -> &mut Output
+ where
+ I: SliceIndex<[MaybeUninit<K>], Output = Output>,
+ {
// SAFETY: the caller will not be able to call further methods on self
// until the key slice reference is dropped, as we have unique access
// for the lifetime of the borrow.
- unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(..len) }
+ unsafe { self.as_leaf_mut().keys.as_mut_slice().get_unchecked_mut(index) }
}
- /// Offers exclusive access to a sized slice of value storage area in the node.
- unsafe fn into_val_area_slice(mut self) -> &'a mut [MaybeUninit<V>] {
- let len = self.len();
+ /// Borrows exclusive access to an element or slice of the node's value storage area.
+ ///
+ /// # Safety
+ /// `index` is in bounds of 0..CAPACITY
+ unsafe fn val_area_mut<I, Output: ?Sized>(&mut self, index: I) -> &mut Output
+ where
+ I: SliceIndex<[MaybeUninit<V>], Output = Output>,
+ {
// SAFETY: the caller will not be able to call further methods on self
// until the value slice reference is dropped, as we have unique access
// for the lifetime of the borrow.
- unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(..len) }
+ unsafe { self.as_leaf_mut().vals.as_mut_slice().get_unchecked_mut(index) }
}
}
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
- /// Offers exclusive access to a sized slice of storage area for edge contents in the node.
- unsafe fn into_edge_area_slice(mut self) -> &'a mut [MaybeUninit<BoxedNode<K, V>>] {
- let len = self.len();
+ /// Borrows exclusive access to an element or slice of the node's storage area for edge contents.
+ ///
+ /// # Safety
+ /// `index` is in bounds of 0..CAPACITY + 1
+ unsafe fn edge_area_mut<I, Output: ?Sized>(&mut self, index: I) -> &mut Output
+ where
+ I: SliceIndex<[MaybeUninit<BoxedNode<K, V>>], Output = Output>,
+ {
// SAFETY: the caller will not be able to call further methods on self
// until the edge slice reference is dropped, as we have unique access
// for the lifetime of the borrow.
- unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(..len + 1) }
+ unsafe { self.as_internal_mut().edges.as_mut_slice().get_unchecked_mut(index) }
}
}
}
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
- /// Exposes exclusive access to the length of the node.
- pub fn into_len_mut(mut self) -> &'a mut u16 {
- &mut (*Self::as_leaf_mut(&mut self)).len
+ /// Borrows exclusive access to the length of the node.
+ pub fn len_mut(&mut self) -> &mut u16 {
+ &mut self.as_leaf_mut().len
}
}
impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
/// Clears the root's link to its parent edge.
fn clear_parent_link(&mut self) {
- let leaf = NodeRef::as_leaf_mut(&mut self.borrow_mut());
+ let mut root_node = self.borrow_mut();
+ let leaf = root_node.as_leaf_mut();
leaf.parent = None;
}
}
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
/// Adds a key-value pair to the end of the node.
pub fn push(&mut self, key: K, val: V) {
- let len = unsafe { self.reborrow_mut().into_len_mut() };
+ let len = self.len_mut();
let idx = usize::from(*len);
assert!(idx < CAPACITY);
*len += 1;
unsafe {
- self.reborrow_mut().into_key_area_mut_at(idx).write(key);
- self.reborrow_mut().into_val_area_mut_at(idx).write(val);
+ self.key_area_mut(idx).write(key);
+ self.val_area_mut(idx).write(val);
}
}
/// Adds a key-value pair to the beginning of the node.
fn push_front(&mut self, key: K, val: V) {
- assert!(self.len() < CAPACITY);
-
+ let new_len = self.len() + 1;
+ assert!(new_len <= CAPACITY);
unsafe {
- *self.reborrow_mut().into_len_mut() += 1;
- slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
- slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
+ slice_insert(self.key_area_mut(..new_len), 0, key);
+ slice_insert(self.val_area_mut(..new_len), 0, val);
+ *self.len_mut() = new_len as u16;
}
}
}
pub fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
assert!(edge.height == self.height - 1);
- let len = unsafe { self.reborrow_mut().into_len_mut() };
+ let len = self.len_mut();
let idx = usize::from(*len);
assert!(idx < CAPACITY);
*len += 1;
unsafe {
- self.reborrow_mut().into_key_area_mut_at(idx).write(key);
- self.reborrow_mut().into_val_area_mut_at(idx).write(val);
- self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node);
+ self.key_area_mut(idx).write(key);
+ self.val_area_mut(idx).write(val);
+ self.edge_area_mut(idx + 1).write(edge.node);
Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
}
}
/// Adds a key-value pair, and an edge to go to the left of that pair,
/// to the beginning of the node.
fn push_front(&mut self, key: K, val: V, edge: Root<K, V>) {
+ let new_len = self.len() + 1;
assert!(edge.height == self.height - 1);
- assert!(self.len() < CAPACITY);
+ assert!(new_len <= CAPACITY);
unsafe {
- *self.reborrow_mut().into_len_mut() += 1;
- slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
- slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
- slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node);
+ slice_insert(self.key_area_mut(..new_len), 0, key);
+ slice_insert(self.val_area_mut(..new_len), 0, val);
+ slice_insert(self.edge_area_mut(..new_len + 1), 0, edge.node);
+ *self.len_mut() = new_len as u16;
}
self.correct_all_childrens_parent_links();
let idx = self.len() - 1;
unsafe {
- let key = ptr::read(self.reborrow().key_at(idx));
- let val = ptr::read(self.reborrow().val_at(idx));
+ let key = self.key_area_mut(idx).assume_init_read();
+ let val = self.val_area_mut(idx).assume_init_read();
let edge = match self.reborrow_mut().force() {
ForceResult::Leaf(_) => None,
- ForceResult::Internal(internal) => {
- let node = ptr::read(internal.reborrow().edge_at(idx + 1));
+ ForceResult::Internal(mut internal) => {
+ let node = internal.edge_area_mut(idx + 1).assume_init_read();
let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
// Currently, clearing the parent link is superfluous, because we will
// insert the node elsewhere and set its parent link again.
}
};
- *self.reborrow_mut().into_len_mut() -= 1;
+ *self.len_mut() -= 1;
(key, val, edge)
}
}
let old_len = self.len();
unsafe {
- let key = slice_remove(self.reborrow_mut().into_key_area_slice(), 0);
- let val = slice_remove(self.reborrow_mut().into_val_area_slice(), 0);
+ let key = slice_remove(self.key_area_mut(..old_len), 0);
+ let val = slice_remove(self.val_area_mut(..old_len), 0);
let edge = match self.reborrow_mut().force() {
ForceResult::Leaf(_) => None,
ForceResult::Internal(mut internal) => {
- let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
+ let node = slice_remove(internal.edge_area_mut(..old_len + 1), 0);
let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
// Currently, clearing the parent link is superfluous, because we will
// insert the node elsewhere and set its parent link again.
}
};
- *self.reborrow_mut().into_len_mut() -= 1;
+ *self.len_mut() -= 1;
(key, val, edge)
}
}
fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) {
- let leaf = Self::as_leaf_mut(&mut self);
+ let leaf = self.as_leaf_mut();
let keys = MaybeUninit::slice_as_mut_ptr(&mut leaf.keys);
let vals = MaybeUninit::slice_as_mut_ptr(&mut leaf.vals);
(keys, vals)
/// The returned pointer points to the inserted value.
fn insert_fit(&mut self, key: K, val: V) -> *mut V {
debug_assert!(self.node.len() < CAPACITY);
+ let new_len = self.node.len() + 1;
unsafe {
- *self.node.reborrow_mut().into_len_mut() += 1;
- slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
- slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
+ slice_insert(self.node.key_area_mut(..new_len), self.idx, key);
+ slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
+ *self.node.len_mut() = new_len as u16;
- self.node.reborrow_mut().into_val_area_mut_at(self.idx).assume_init_mut()
+ self.node.val_area_mut(self.idx).assume_init_mut()
}
}
}
fn insert_fit(&mut self, key: K, val: V, edge: Root<K, V>) {
debug_assert!(self.node.len() < CAPACITY);
debug_assert!(edge.height == self.node.height - 1);
+ let new_len = self.node.len() + 1;
unsafe {
- *self.node.reborrow_mut().into_len_mut() += 1;
- slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
- slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
- slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node);
+ slice_insert(self.node.key_area_mut(..new_len), self.idx, key);
+ slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
+ slice_insert(self.node.edge_area_mut(..new_len + 1), self.idx + 1, edge.node);
+ *self.node.len_mut() = new_len as u16;
- self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
+ self.node.correct_childrens_parent_links(self.idx + 1..new_len + 1);
}
}
}
impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
- pub fn into_key_mut(self) -> &'a mut K {
- unsafe { self.node.into_key_area_mut_at(self.idx).assume_init_mut() }
+ pub fn key_mut(&mut self) -> &mut K {
+ unsafe { self.node.key_area_mut(self.idx).assume_init_mut() }
}
pub fn into_val_mut(self) -> &'a mut V {
- unsafe { self.node.into_val_area_mut_at(self.idx).assume_init_mut() }
+ let leaf = self.node.into_leaf_mut();
+ unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
}
}
// We cannot call separate key and value methods, because calling the second one
// invalidates the reference returned by the first.
unsafe {
- let leaf = NodeRef::as_leaf_mut(&mut self.node.reborrow_mut());
+ let leaf = self.node.as_leaf_mut();
let key = leaf.keys.get_unchecked_mut(self.idx).assume_init_mut();
let val = leaf.vals.get_unchecked_mut(self.idx).assume_init_mut();
(key, val)
}
impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
- /// Helps implementations of `split` for a particular `NodeType`,
- /// by calculating the length of the new node.
- fn split_new_node_len(&self) -> usize {
- debug_assert!(self.idx < self.node.len());
- self.node.len() - self.idx - 1
- }
-
/// Helps implementations of `split` for a particular `NodeType`,
/// by taking care of leaf data.
fn split_leaf_data(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V) {
- let new_len = self.split_new_node_len();
+ debug_assert!(self.idx < self.node.len());
+ let new_len = self.node.len() - self.idx - 1;
new_node.len = new_len as u16;
unsafe {
- let k = ptr::read(self.node.reborrow().key_at(self.idx));
- let v = ptr::read(self.node.reborrow().val_at(self.idx));
+ let k = self.node.key_area_mut(self.idx).assume_init_read();
+ let v = self.node.val_area_mut(self.idx).assume_init_read();
ptr::copy_nonoverlapping(
- self.node.reborrow().key_area().as_ptr().add(self.idx + 1),
+ self.node.key_area_mut(self.idx + 1..).as_ptr(),
new_node.keys.as_mut_ptr(),
new_len,
);
ptr::copy_nonoverlapping(
- self.node.reborrow().val_area().as_ptr().add(self.idx + 1),
+ self.node.val_area_mut(self.idx + 1..).as_ptr(),
new_node.vals.as_mut_ptr(),
new_len,
);
- *self.node.reborrow_mut().into_len_mut() = self.idx as u16;
+ *self.node.len_mut() = self.idx as u16;
(k, v)
}
}
pub fn remove(
mut self,
) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
+ let old_len = self.node.len();
unsafe {
- let k = slice_remove(self.node.reborrow_mut().into_key_area_slice(), self.idx);
- let v = slice_remove(self.node.reborrow_mut().into_val_area_slice(), self.idx);
- *self.node.reborrow_mut().into_len_mut() -= 1;
+ let k = slice_remove(self.node.key_area_mut(..old_len), self.idx);
+ let v = slice_remove(self.node.val_area_mut(..old_len), self.idx);
+ *self.node.len_mut() = (old_len - 1) as u16;
((k, v), self.left_edge())
}
}
pub fn split(mut self) -> SplitResult<'a, K, V, marker::Internal> {
unsafe {
let mut new_node = Box::new(InternalNode::new());
- let new_len = self.split_new_node_len();
- // Move edges out before reducing length:
+ let kv = self.split_leaf_data(&mut new_node.data);
+ let new_len = usize::from(new_node.data.len);
ptr::copy_nonoverlapping(
- self.node.reborrow().edge_area().as_ptr().add(self.idx + 1),
+ self.node.edge_area_mut(self.idx + 1..).as_ptr(),
new_node.edges.as_mut_ptr(),
new_len + 1,
);
- let kv = self.split_leaf_data(&mut new_node.data);
let height = self.node.height;
let mut right = NodeRef::from_new_internal(new_node, height);
let old_parent_len = parent_node.len();
let mut left_node = self.left_child;
let old_left_len = left_node.len();
- let right_node = self.right_child;
+ let mut right_node = self.right_child;
let right_len = right_node.len();
let new_left_len = old_left_len + 1 + right_len;
});
unsafe {
- *left_node.reborrow_mut().into_len_mut() = new_left_len as u16;
+ *left_node.len_mut() = new_left_len as u16;
- let parent_key =
- slice_remove(parent_node.reborrow_mut().into_key_area_slice(), parent_idx);
- left_node.reborrow_mut().into_key_area_mut_at(old_left_len).write(parent_key);
+ let parent_key = slice_remove(parent_node.key_area_mut(..old_parent_len), parent_idx);
+ left_node.key_area_mut(old_left_len).write(parent_key);
ptr::copy_nonoverlapping(
- right_node.reborrow().key_area().as_ptr(),
- left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(old_left_len + 1),
+ right_node.key_area_mut(..).as_ptr(),
+ left_node.key_area_mut(old_left_len + 1..).as_mut_ptr(),
right_len,
);
- let parent_val =
- slice_remove(parent_node.reborrow_mut().into_val_area_slice(), parent_idx);
- left_node.reborrow_mut().into_val_area_mut_at(old_left_len).write(parent_val);
+ let parent_val = slice_remove(parent_node.val_area_mut(..old_parent_len), parent_idx);
+ left_node.val_area_mut(old_left_len).write(parent_val);
ptr::copy_nonoverlapping(
- right_node.reborrow().val_area().as_ptr(),
- left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(old_left_len + 1),
+ right_node.val_area_mut(..).as_ptr(),
+ left_node.val_area_mut(old_left_len + 1..).as_mut_ptr(),
right_len,
);
- slice_remove(&mut parent_node.reborrow_mut().into_edge_area_slice(), parent_idx + 1);
+ slice_remove(&mut parent_node.edge_area_mut(..old_parent_len + 1), parent_idx + 1);
parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len);
- *parent_node.reborrow_mut().into_len_mut() -= 1;
+ *parent_node.len_mut() -= 1;
if parent_node.height > 1 {
// SAFETY: the height of the nodes being merged is one below the height
// of the node of this edge, thus above zero, so they are internal.
let mut left_node = left_node.reborrow_mut().cast_to_internal_unchecked();
- let right_node = right_node.cast_to_internal_unchecked();
+ let mut right_node = right_node.cast_to_internal_unchecked();
ptr::copy_nonoverlapping(
- right_node.reborrow().edge_area().as_ptr(),
- left_node
- .reborrow_mut()
- .into_edge_area_slice()
- .as_mut_ptr()
- .add(old_left_len + 1),
+ right_node.edge_area_mut(..).as_ptr(),
+ left_node.edge_area_mut(old_left_len + 1..).as_mut_ptr(),
right_len + 1,
);
assert!(old_left_len >= count);
let new_left_len = old_left_len - count;
+ let new_right_len = old_right_len + count;
+ *left_node.len_mut() = new_left_len as u16;
+ *right_node.len_mut() = new_right_len as u16;
// Move leaf data.
{
move_kv(left_kv, new_left_len, parent_kv, 0, 1);
}
- *left_node.reborrow_mut().into_len_mut() -= count as u16;
- *right_node.reborrow_mut().into_len_mut() += count as u16;
-
match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) {
(ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
// Make room for stolen edges.
- let left = left.reborrow();
- let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
+ let right_edges = right.edge_area_mut(..).as_mut_ptr();
ptr::copy(right_edges, right_edges.add(count), old_right_len + 1);
- right.correct_childrens_parent_links(count..count + old_right_len + 1);
+ right.correct_childrens_parent_links(count..new_right_len + 1);
// Steal edges.
move_edges(left, new_left_len + 1, right, 0, count);
assert!(old_left_len + count <= CAPACITY);
assert!(old_right_len >= count);
+ let new_left_len = old_left_len + count;
let new_right_len = old_right_len - count;
+ *left_node.len_mut() = new_left_len as u16;
+ *right_node.len_mut() = new_right_len as u16;
// Move leaf data.
{
ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len);
}
- *left_node.reborrow_mut().into_len_mut() += count as u16;
- *right_node.reborrow_mut().into_len_mut() -= count as u16;
-
match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) {
(ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
// Steal edges.
- move_edges(right.reborrow(), 0, left, old_left_len + 1, count);
+ move_edges(right.reborrow_mut(), 0, left, old_left_len + 1, count);
// Fill gap where stolen edges used to be.
- let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
+ let right_edges = right.edge_area_mut(..).as_mut_ptr();
ptr::copy(right_edges.add(count), right_edges, new_right_len + 1);
right.correct_childrens_parent_links(0..=new_right_len);
}
// Source and destination must have the same height.
unsafe fn move_edges<'a, K: 'a, V: 'a>(
- source: NodeRef<marker::Immut<'a>, K, V, marker::Internal>,
+ mut source: NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
source_offset: usize,
mut dest: NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
dest_offset: usize,
count: usize,
) {
unsafe {
- let source_ptr = source.edge_area().as_ptr();
- let dest_ptr = dest.reborrow_mut().into_edge_area_slice().as_mut_ptr();
- ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
+ let source_ptr = source.edge_area_mut(..).as_ptr();
+ let dest_ptr = dest.edge_area_mut(dest_offset..).as_mut_ptr();
+ ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr, count);
dest.correct_childrens_parent_links(dest_offset..dest_offset + count);
}
}
move_kv(left_kv, new_left_len, right_kv, 0, new_right_len);
- *left_node.reborrow_mut().into_len_mut() = new_left_len as u16;
- *right_node.reborrow_mut().into_len_mut() = new_right_len as u16;
+ *left_node.len_mut() = new_left_len as u16;
+ *right_node.len_mut() = new_right_len as u16;
match (left_node.force(), right_node.force()) {
(ForceResult::Internal(left), ForceResult::Internal(right)) => {
- let left = left.reborrow();
move_edges(left, new_left_len + 1, right, 1, new_right_len);
}
(ForceResult::Leaf(_), ForceResult::Leaf(_)) => {}
let depth = self.height();
let indent = " ".repeat(depth);
result += &format!("\n{}", indent);
- for idx in 0..leaf.len() {
- if idx > 0 {
- result += ", ";
+ if leaf.len() == 0 {
+ result += "(empty node)";
+ } else {
+ for idx in 0..leaf.len() {
+ if idx > 0 {
+ result += ", ";
+ }
+ result += &format!("{:?}", unsafe { leaf.key_at(idx) });
}
- result += &format!("{:?}", unsafe { leaf.key_at(idx) });
}
}
navigate::Position::Internal(_) => {}
/// v.insert(1);
/// assert_eq!(v.len(), 1);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn len(&self) -> usize {
assert_eq!(a.pop_last(), None);
}
+// Unlike the function with the same name in map/tests, returns no values.
+// Which also means it returns different predetermined pseudo-random keys,
+// and the test cases using this function explore slightly different trees.
fn rand_data(len: usize) -> Vec<u32> {
- assert!(len <= 70029); // from that point on numbers repeat
let mut rng = DeterministicRng::new();
Vec::from_iter((0..len).map(|_| rng.next()))
}
}
}
+ /// Stock up or merge away any underfull nodes on the right border of the
+ /// tree. The other nodes, those that are not the root nor a rightmost edge,
+ /// must already have at least MIN_LEN elements.
fn fix_right_border(&mut self) {
self.fix_top();
}
cur_node = last_kv.into_right_child();
}
+ debug_assert!(cur_node.len() > MIN_LEN);
}
}
}
cur_node = first_kv.into_left_child();
}
+ debug_assert!(cur_node.len() > MIN_LEN);
}
}
/// dl.push_back(3);
/// assert_eq!(dl.len(), 3);
/// ```
+ #[doc(alias = "length")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
/// v.push_back(1);
/// assert_eq!(v.len(), 1);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
count(self.tail, self.head, self.cap())
/// # Examples
///
/// ```
- /// #![feature(deque_range)]
- ///
/// use std::collections::VecDeque;
///
/// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
/// assert_eq!(all.len(), 3);
/// ```
#[inline]
- #[unstable(feature = "deque_range", issue = "74217")]
+ #[stable(feature = "deque_range", since = "1.51.0")]
pub fn range<R>(&self, range: R) -> Iter<'_, T>
where
R: RangeBounds<usize>,
/// # Examples
///
/// ```
- /// #![feature(deque_range)]
- ///
/// use std::collections::VecDeque;
///
/// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
/// assert_eq!(v, vec![2, 4, 12]);
/// ```
#[inline]
- #[unstable(feature = "deque_range", issue = "74217")]
+ #[stable(feature = "deque_range", since = "1.51.0")]
pub fn range_mut<R>(&mut self, range: R) -> IterMut<'_, T>
where
R: RangeBounds<usize>,
#![feature(never_type)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
strong: &'a Cell<usize>,
}
-impl<T: ?Sized> Weak<T> {
+impl<T> Weak<T> {
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
///
/// The pointer is valid only if there are some strong references. The pointer may be dangling,
// SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
}
+}
+impl<T: ?Sized> Weak<T> {
/// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
/// dropping of the inner value if successful.
///
// the strong pointers have disappeared.
if inner.weak() == 0 {
unsafe {
- Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
+ Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr()));
}
}
}
}
}
-#[test]
-fn test_into_from_weak_raw_unsized() {
- use std::fmt::Display;
- use std::string::ToString;
-
- let arc: Rc<str> = Rc::from("foo");
- let weak: Weak<str> = Rc::downgrade(&arc);
-
- let ptr = Weak::into_raw(weak.clone());
- let weak2 = unsafe { Weak::from_raw(ptr) };
-
- assert_eq!(unsafe { &*ptr }, "foo");
- assert!(weak.ptr_eq(&weak2));
-
- let arc: Rc<dyn Display> = Rc::new(123);
- let weak: Weak<dyn Display> = Rc::downgrade(&arc);
-
- let ptr = Weak::into_raw(weak.clone());
- let weak2 = unsafe { Weak::from_raw(ptr) };
-
- assert_eq!(unsafe { &*ptr }.to_string(), "123");
- assert!(weak.ptr_eq(&weak2));
-}
-
#[test]
fn get_mut() {
let mut x = Rc::new(3);
/// assert_eq!(fancy_f.len(), 4);
/// assert_eq!(fancy_f.chars().count(), 3);
/// ```
+ #[doc(alias = "length")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
use core::intrinsics::abort;
use core::iter;
use core::marker::{PhantomData, Unpin, Unsize};
-use core::mem::{self, align_of_val, size_of_val};
+use core::mem::{self, align_of_val_raw, size_of_val};
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
use core::pin::Pin;
use core::ptr::{self, NonNull};
strong: &'a atomic::AtomicUsize,
}
-impl<T: ?Sized> Weak<T> {
+impl<T> Weak<T> {
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
///
/// The pointer is valid only if there are some strong references. The pointer may be dangling,
// SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } }
}
+}
+impl<T: ?Sized> Weak<T> {
/// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying
/// dropping of the inner value if successful.
///
if inner.weak.fetch_sub(1, Release) == 1 {
acquire!(inner.weak);
- unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) }
+ unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())) }
}
}
}
// Because it is `?Sized`, it will always be the last field in memory.
// Note: This is a detail of the current implementation of the compiler,
// and is not a guaranteed language detail. Do not rely on it outside of std.
- unsafe { data_offset_align(align_of_val(&*ptr)) }
+ unsafe { data_offset_align(align_of_val_raw(ptr)) }
}
#[inline]
}
}
-#[test]
-fn test_into_from_weak_raw_unsized() {
- use std::fmt::Display;
- use std::string::ToString;
-
- let arc: Arc<str> = Arc::from("foo");
- let weak: Weak<str> = Arc::downgrade(&arc);
-
- let ptr = Weak::into_raw(weak.clone());
- let weak2 = unsafe { Weak::from_raw(ptr) };
-
- assert_eq!(unsafe { &*ptr }, "foo");
- assert!(weak.ptr_eq(&weak2));
-
- let arc: Arc<dyn Display> = Arc::new(123);
- let weak: Weak<dyn Display> = Arc::downgrade(&arc);
-
- let ptr = Weak::into_raw(weak.clone());
- let weak2 = unsafe { Weak::from_raw(ptr) };
-
- assert_eq!(unsafe { &*ptr }.to_string(), "123");
- assert!(weak.ptr_eq(&weak2));
-}
-
#[test]
fn test_cowarc_clone_make_mut() {
let mut cow0 = Arc::new(75);
+++ /dev/null
-// ignore-tidy-filelength
-//! A contiguous growable array type with heap-allocated contents, written
-//! `Vec<T>`.
-//!
-//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and
-//! `O(1)` pop (from the end).
-//!
-//! Vectors ensure they never allocate more than `isize::MAX` bytes.
-//!
-//! # Examples
-//!
-//! You can explicitly create a [`Vec`] with [`Vec::new`]:
-//!
-//! ```
-//! let v: Vec<i32> = Vec::new();
-//! ```
-//!
-//! ...or by using the [`vec!`] macro:
-//!
-//! ```
-//! let v: Vec<i32> = vec![];
-//!
-//! let v = vec![1, 2, 3, 4, 5];
-//!
-//! let v = vec![0; 10]; // ten zeroes
-//! ```
-//!
-//! You can [`push`] values onto the end of a vector (which will grow the vector
-//! as needed):
-//!
-//! ```
-//! let mut v = vec![1, 2];
-//!
-//! v.push(3);
-//! ```
-//!
-//! Popping values works in much the same way:
-//!
-//! ```
-//! let mut v = vec![1, 2];
-//!
-//! let two = v.pop();
-//! ```
-//!
-//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits):
-//!
-//! ```
-//! let mut v = vec![1, 2, 3];
-//! let three = v[2];
-//! v[1] = v[1] + 5;
-//! ```
-//!
-//! [`push`]: Vec::push
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use core::cmp::{self, Ordering};
-use core::convert::TryFrom;
-use core::fmt;
-use core::hash::{Hash, Hasher};
-use core::intrinsics::{arith_offset, assume};
-use core::iter::{
- FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess,
-};
-use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop, MaybeUninit};
-use core::ops::{self, Index, IndexMut, Range, RangeBounds};
-use core::ptr::{self, NonNull};
-use core::slice::{self, SliceIndex};
-
-use crate::alloc::{Allocator, Global};
-use crate::borrow::{Cow, ToOwned};
-use crate::boxed::Box;
-use crate::collections::TryReserveError;
-use crate::raw_vec::RawVec;
-
-/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
-///
-/// # Examples
-///
-/// ```
-/// let mut vec = Vec::new();
-/// vec.push(1);
-/// vec.push(2);
-///
-/// assert_eq!(vec.len(), 2);
-/// assert_eq!(vec[0], 1);
-///
-/// assert_eq!(vec.pop(), Some(2));
-/// assert_eq!(vec.len(), 1);
-///
-/// vec[0] = 7;
-/// assert_eq!(vec[0], 7);
-///
-/// vec.extend([1, 2, 3].iter().copied());
-///
-/// for x in &vec {
-/// println!("{}", x);
-/// }
-/// assert_eq!(vec, [7, 1, 2, 3]);
-/// ```
-///
-/// The [`vec!`] macro is provided to make initialization more convenient:
-///
-/// ```
-/// let mut vec = vec![1, 2, 3];
-/// vec.push(4);
-/// assert_eq!(vec, [1, 2, 3, 4]);
-/// ```
-///
-/// It can also initialize each element of a `Vec<T>` with a given value.
-/// This may be more efficient than performing allocation and initialization
-/// in separate steps, especially when initializing a vector of zeros:
-///
-/// ```
-/// let vec = vec![0; 5];
-/// assert_eq!(vec, [0, 0, 0, 0, 0]);
-///
-/// // The following is equivalent, but potentially slower:
-/// let mut vec = Vec::with_capacity(5);
-/// vec.resize(5, 0);
-/// assert_eq!(vec, [0, 0, 0, 0, 0]);
-/// ```
-///
-/// For more information, see
-/// [Capacity and Reallocation](#capacity-and-reallocation).
-///
-/// Use a `Vec<T>` as an efficient stack:
-///
-/// ```
-/// let mut stack = Vec::new();
-///
-/// stack.push(1);
-/// stack.push(2);
-/// stack.push(3);
-///
-/// while let Some(top) = stack.pop() {
-/// // Prints 3, 2, 1
-/// println!("{}", top);
-/// }
-/// ```
-///
-/// # Indexing
-///
-/// The `Vec` type allows to access values by index, because it implements the
-/// [`Index`] trait. An example will be more explicit:
-///
-/// ```
-/// let v = vec![0, 2, 4, 6];
-/// println!("{}", v[1]); // it will display '2'
-/// ```
-///
-/// However be careful: if you try to access an index which isn't in the `Vec`,
-/// your software will panic! You cannot do this:
-///
-/// ```should_panic
-/// let v = vec![0, 2, 4, 6];
-/// println!("{}", v[6]); // it will panic!
-/// ```
-///
-/// Use [`get`] and [`get_mut`] if you want to check whether the index is in
-/// the `Vec`.
-///
-/// # Slicing
-///
-/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects.
-/// To get a [slice], use [`&`]. Example:
-///
-/// ```
-/// fn read_slice(slice: &[usize]) {
-/// // ...
-/// }
-///
-/// let v = vec![0, 1];
-/// read_slice(&v);
-///
-/// // ... and that's all!
-/// // you can also do it like this:
-/// let u: &[usize] = &v;
-/// // or like this:
-/// let u: &[_] = &v;
-/// ```
-///
-/// In Rust, it's more common to pass slices as arguments rather than vectors
-/// when you just want to provide read access. The same goes for [`String`] and
-/// [`&str`].
-///
-/// # Capacity and reallocation
-///
-/// The capacity of a vector is the amount of space allocated for any future
-/// elements that will be added onto the vector. This is not to be confused with
-/// the *length* of a vector, which specifies the number of actual elements
-/// within the vector. If a vector's length exceeds its capacity, its capacity
-/// will automatically be increased, but its elements will have to be
-/// reallocated.
-///
-/// For example, a vector with capacity 10 and length 0 would be an empty vector
-/// with space for 10 more elements. Pushing 10 or fewer elements onto the
-/// vector will not change its capacity or cause reallocation to occur. However,
-/// if the vector's length is increased to 11, it will have to reallocate, which
-/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`]
-/// whenever possible to specify how big the vector is expected to get.
-///
-/// # Guarantees
-///
-/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees
-/// about its design. This ensures that it's as low-overhead as possible in
-/// the general case, and can be correctly manipulated in primitive ways
-/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<T>`.
-/// If additional type parameters are added (e.g., to support custom allocators),
-/// overriding their defaults may change the behavior.
-///
-/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length)
-/// triplet. No more, no less. The order of these fields is completely
-/// unspecified, and you should use the appropriate methods to modify these.
-/// The pointer will never be null, so this type is null-pointer-optimized.
-///
-/// However, the pointer may not actually point to allocated memory. In particular,
-/// if you construct a `Vec` with capacity 0 via [`Vec::new`], [`vec![]`][`vec!`],
-/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit`]
-/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
-/// types inside a `Vec`, it will not allocate space for them. *Note that in this case
-/// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only
-/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation
-/// details are very subtle — if you intend to allocate memory using a `Vec`
-/// and use it for something else (either to pass to unsafe code, or to build your
-/// own memory-backed collection), be sure to deallocate this memory by using
-/// `from_raw_parts` to recover the `Vec` and then dropping it.
-///
-/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
-/// (as defined by the allocator Rust is configured to use by default), and its
-/// pointer points to [`len`] initialized, contiguous elements in order (what
-/// you would see if you coerced it to a slice), followed by [`capacity`]` -
-/// `[`len`] logically uninitialized, contiguous elements.
-///
-/// `Vec` will never perform a "small optimization" where elements are actually
-/// stored on the stack for two reasons:
-///
-/// * It would make it more difficult for unsafe code to correctly manipulate
-/// a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were
-/// only moved, and it would be more difficult to determine if a `Vec` had
-/// actually allocated memory.
-///
-/// * It would penalize the general case, incurring an additional branch
-/// on every access.
-///
-/// `Vec` will never automatically shrink itself, even if completely empty. This
-/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec`
-/// and then filling it back up to the same [`len`] should incur no calls to
-/// the allocator. If you wish to free up unused memory, use
-/// [`shrink_to_fit`].
-///
-/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
-/// sufficient. [`push`] and [`insert`] *will* (re)allocate if
-/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely
-/// accurate, and can be relied on. It can even be used to manually free the memory
-/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
-/// when not necessary.
-///
-/// `Vec` does not guarantee any particular growth strategy when reallocating
-/// when full, nor when [`reserve`] is called. The current strategy is basic
-/// and it may prove desirable to use a non-constant growth factor. Whatever
-/// strategy is used will of course guarantee *O*(1) amortized [`push`].
-///
-/// `vec![x; n]`, `vec![a, b, c, d]`, and
-/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
-/// with exactly the requested capacity. If [`len`]` == `[`capacity`],
-/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
-/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
-///
-/// `Vec` will not specifically overwrite any data that is removed from it,
-/// but also won't specifically preserve it. Its uninitialized memory is
-/// scratch space that it may use however it wants. It will generally just do
-/// whatever is most efficient or otherwise easy to implement. Do not rely on
-/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
-/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
-/// first, that may not actually happen because the optimizer does not consider
-/// this a side-effect that must be preserved. There is one case which we will
-/// not break, however: using `unsafe` code to write to the excess capacity,
-/// and then increasing the length to match, is always valid.
-///
-/// `Vec` does not currently guarantee the order in which elements are dropped.
-/// The order has changed in the past and may change again.
-///
-/// [`get`]: ../../std/vec/struct.Vec.html#method.get
-/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut
-/// [`String`]: crate::string::String
-/// [`&str`]: type@str
-/// [`shrink_to_fit`]: Vec::shrink_to_fit
-/// [`capacity`]: Vec::capacity
-/// [`mem::size_of::<T>`]: core::mem::size_of
-/// [`len`]: Vec::len
-/// [`push`]: Vec::push
-/// [`insert`]: Vec::insert
-/// [`reserve`]: Vec::reserve
-/// [owned slice]: Box
-/// [slice]: ../../std/primitive.slice.html
-/// [`&`]: ../../std/primitive.reference.html
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
-pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- buf: RawVec<T, A>,
- len: usize,
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Inherent methods
-////////////////////////////////////////////////////////////////////////////////
-
-impl<T> Vec<T> {
- /// Constructs a new, empty `Vec<T>`.
- ///
- /// The vector will not allocate until elements are pushed onto it.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![allow(unused_mut)]
- /// let mut vec: Vec<i32> = Vec::new();
- /// ```
- #[inline]
- #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub const fn new() -> Self {
- Vec { buf: RawVec::NEW, len: 0 }
- }
-
- /// Constructs a new, empty `Vec<T>` with the specified capacity.
- ///
- /// The vector will be able to hold exactly `capacity` elements without
- /// reallocating. If `capacity` is 0, the vector will not allocate.
- ///
- /// It is important to note that although the returned vector has the
- /// *capacity* specified, the vector will have a zero *length*. For an
- /// explanation of the difference between length and capacity, see
- /// *[Capacity and reallocation]*.
- ///
- /// [Capacity and reallocation]: #capacity-and-reallocation
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = Vec::with_capacity(10);
- ///
- /// // The vector contains no items, even though it has capacity for more
- /// assert_eq!(vec.len(), 0);
- /// assert_eq!(vec.capacity(), 10);
- ///
- /// // These are all done without reallocating...
- /// for i in 0..10 {
- /// vec.push(i);
- /// }
- /// assert_eq!(vec.len(), 10);
- /// assert_eq!(vec.capacity(), 10);
- ///
- /// // ...but this may make the vector reallocate
- /// vec.push(11);
- /// assert_eq!(vec.len(), 11);
- /// assert!(vec.capacity() >= 11);
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn with_capacity(capacity: usize) -> Self {
- Self::with_capacity_in(capacity, Global)
- }
-
- /// Creates a `Vec<T>` directly from the raw components of another vector.
- ///
- /// # Safety
- ///
- /// This is highly unsafe, due to the number of invariants that aren't
- /// checked:
- ///
- /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
- /// (at least, it's highly likely to be incorrect if it wasn't).
- /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
- /// (`T` having a less strict alignment is not sufficient, the alignment really
- /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
- /// allocated and deallocated with the same layout.)
- /// * `length` needs to be less than or equal to `capacity`.
- /// * `capacity` needs to be the capacity that the pointer was allocated with.
- ///
- /// Violating these may cause problems like corrupting the allocator's
- /// internal data structures. For example it is **not** safe
- /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
- /// It's also not safe to build one from a `Vec<u16>` and its length, because
- /// the allocator cares about the alignment, and these two types have different
- /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
- /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
- ///
- /// The ownership of `ptr` is effectively transferred to the
- /// `Vec<T>` which may then deallocate, reallocate or change the
- /// contents of memory pointed to by the pointer at will. Ensure
- /// that nothing else uses the pointer after calling this
- /// function.
- ///
- /// [`String`]: crate::string::String
- /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ptr;
- /// use std::mem;
- ///
- /// let v = vec![1, 2, 3];
- ///
- // FIXME Update this when vec_into_raw_parts is stabilized
- /// // Prevent running `v`'s destructor so we are in complete control
- /// // of the allocation.
- /// let mut v = mem::ManuallyDrop::new(v);
- ///
- /// // Pull out the various important pieces of information about `v`
- /// let p = v.as_mut_ptr();
- /// let len = v.len();
- /// let cap = v.capacity();
- ///
- /// unsafe {
- /// // Overwrite memory with 4, 5, 6
- /// for i in 0..len as isize {
- /// ptr::write(p.offset(i), 4 + i);
- /// }
- ///
- /// // Put everything back together into a Vec
- /// let rebuilt = Vec::from_raw_parts(p, len, cap);
- /// assert_eq!(rebuilt, [4, 5, 6]);
- /// }
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
- unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }
- }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
- /// Constructs a new, empty `Vec<T, A>`.
- ///
- /// The vector will not allocate until elements are pushed onto it.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(allocator_api)]
- ///
- /// use std::alloc::System;
- ///
- /// # #[allow(unused_mut)]
- /// let mut vec: Vec<i32, _> = Vec::new_in(System);
- /// ```
- #[inline]
- #[unstable(feature = "allocator_api", issue = "32838")]
- pub const fn new_in(alloc: A) -> Self {
- Vec { buf: RawVec::new_in(alloc), len: 0 }
- }
-
- /// Constructs a new, empty `Vec<T, A>` with the specified capacity with the provided
- /// allocator.
- ///
- /// The vector will be able to hold exactly `capacity` elements without
- /// reallocating. If `capacity` is 0, the vector will not allocate.
- ///
- /// It is important to note that although the returned vector has the
- /// *capacity* specified, the vector will have a zero *length*. For an
- /// explanation of the difference between length and capacity, see
- /// *[Capacity and reallocation]*.
- ///
- /// [Capacity and reallocation]: #capacity-and-reallocation
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(allocator_api)]
- ///
- /// use std::alloc::System;
- ///
- /// let mut vec = Vec::with_capacity_in(10, System);
- ///
- /// // The vector contains no items, even though it has capacity for more
- /// assert_eq!(vec.len(), 0);
- /// assert_eq!(vec.capacity(), 10);
- ///
- /// // These are all done without reallocating...
- /// for i in 0..10 {
- /// vec.push(i);
- /// }
- /// assert_eq!(vec.len(), 10);
- /// assert_eq!(vec.capacity(), 10);
- ///
- /// // ...but this may make the vector reallocate
- /// vec.push(11);
- /// assert_eq!(vec.len(), 11);
- /// assert!(vec.capacity() >= 11);
- /// ```
- #[inline]
- #[unstable(feature = "allocator_api", issue = "32838")]
- pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
- Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
- }
-
- /// Creates a `Vec<T, A>` directly from the raw components of another vector.
- ///
- /// # Safety
- ///
- /// This is highly unsafe, due to the number of invariants that aren't
- /// checked:
- ///
- /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
- /// (at least, it's highly likely to be incorrect if it wasn't).
- /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
- /// (`T` having a less strict alignment is not sufficient, the alignment really
- /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
- /// allocated and deallocated with the same layout.)
- /// * `length` needs to be less than or equal to `capacity`.
- /// * `capacity` needs to be the capacity that the pointer was allocated with.
- ///
- /// Violating these may cause problems like corrupting the allocator's
- /// internal data structures. For example it is **not** safe
- /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
- /// It's also not safe to build one from a `Vec<u16>` and its length, because
- /// the allocator cares about the alignment, and these two types have different
- /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
- /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
- ///
- /// The ownership of `ptr` is effectively transferred to the
- /// `Vec<T>` which may then deallocate, reallocate or change the
- /// contents of memory pointed to by the pointer at will. Ensure
- /// that nothing else uses the pointer after calling this
- /// function.
- ///
- /// [`String`]: crate::string::String
- /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(allocator_api)]
- ///
- /// use std::alloc::System;
- ///
- /// use std::ptr;
- /// use std::mem;
- ///
- /// let mut v = Vec::with_capacity_in(3, System);
- /// v.push(1);
- /// v.push(2);
- /// v.push(3);
- ///
- // FIXME Update this when vec_into_raw_parts is stabilized
- /// // Prevent running `v`'s destructor so we are in complete control
- /// // of the allocation.
- /// let mut v = mem::ManuallyDrop::new(v);
- ///
- /// // Pull out the various important pieces of information about `v`
- /// let p = v.as_mut_ptr();
- /// let len = v.len();
- /// let cap = v.capacity();
- /// let alloc = v.allocator();
- ///
- /// unsafe {
- /// // Overwrite memory with 4, 5, 6
- /// for i in 0..len as isize {
- /// ptr::write(p.offset(i), 4 + i);
- /// }
- ///
- /// // Put everything back together into a Vec
- /// let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone());
- /// assert_eq!(rebuilt, [4, 5, 6]);
- /// }
- /// ```
- #[inline]
- #[unstable(feature = "allocator_api", issue = "32838")]
- pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
- unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
- }
-
- /// Decomposes a `Vec<T>` into its raw components.
- ///
- /// Returns the raw pointer to the underlying data, the length of
- /// the vector (in elements), and the allocated capacity of the
- /// data (in elements). These are the same arguments in the same
- /// order as the arguments to [`from_raw_parts`].
- ///
- /// After calling this function, the caller is responsible for the
- /// memory previously managed by the `Vec`. The only way to do
- /// this is to convert the raw pointer, length, and capacity back
- /// into a `Vec` with the [`from_raw_parts`] function, allowing
- /// the destructor to perform the cleanup.
- ///
- /// [`from_raw_parts`]: Vec::from_raw_parts
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(vec_into_raw_parts)]
- /// let v: Vec<i32> = vec![-1, 0, 1];
- ///
- /// let (ptr, len, cap) = v.into_raw_parts();
- ///
- /// let rebuilt = unsafe {
- /// // We can now make changes to the components, such as
- /// // transmuting the raw pointer to a compatible type.
- /// let ptr = ptr as *mut u32;
- ///
- /// Vec::from_raw_parts(ptr, len, cap)
- /// };
- /// assert_eq!(rebuilt, [4294967295, 0, 1]);
- /// ```
- #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
- pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
- let mut me = ManuallyDrop::new(self);
- (me.as_mut_ptr(), me.len(), me.capacity())
- }
-
- /// Decomposes a `Vec<T>` into its raw components.
- ///
- /// Returns the raw pointer to the underlying data, the length of the vector (in elements),
- /// the allocated capacity of the data (in elements), and the allocator. These are the same
- /// arguments in the same order as the arguments to [`from_raw_parts_in`].
- ///
- /// After calling this function, the caller is responsible for the
- /// memory previously managed by the `Vec`. The only way to do
- /// this is to convert the raw pointer, length, and capacity back
- /// into a `Vec` with the [`from_raw_parts_in`] function, allowing
- /// the destructor to perform the cleanup.
- ///
- /// [`from_raw_parts_in`]: Vec::from_raw_parts_in
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(allocator_api, vec_into_raw_parts)]
- ///
- /// use std::alloc::System;
- ///
- /// let mut v: Vec<i32, System> = Vec::new_in(System);
- /// v.push(-1);
- /// v.push(0);
- /// v.push(1);
- ///
- /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
- ///
- /// let rebuilt = unsafe {
- /// // We can now make changes to the components, such as
- /// // transmuting the raw pointer to a compatible type.
- /// let ptr = ptr as *mut u32;
- ///
- /// Vec::from_raw_parts_in(ptr, len, cap, alloc)
- /// };
- /// assert_eq!(rebuilt, [4294967295, 0, 1]);
- /// ```
- #[unstable(feature = "allocator_api", issue = "32838")]
- // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
- pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) {
- let mut me = ManuallyDrop::new(self);
- let len = me.len();
- let capacity = me.capacity();
- let ptr = me.as_mut_ptr();
- let alloc = unsafe { ptr::read(me.allocator()) };
- (ptr, len, capacity, alloc)
- }
-
- /// Returns the number of elements the vector can hold without
- /// reallocating.
- ///
- /// # Examples
- ///
- /// ```
- /// let vec: Vec<i32> = Vec::with_capacity(10);
- /// assert_eq!(vec.capacity(), 10);
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn capacity(&self) -> usize {
- self.buf.capacity()
- }
-
- /// Reserves capacity for at least `additional` more elements to be inserted
- /// in the given `Vec<T>`. The collection may reserve more space to avoid
- /// frequent reallocations. After calling `reserve`, capacity will be
- /// greater than or equal to `self.len() + additional`. Does nothing if
- /// capacity is already sufficient.
- ///
- /// # Panics
- ///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1];
- /// vec.reserve(10);
- /// assert!(vec.capacity() >= 11);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn reserve(&mut self, additional: usize) {
- self.buf.reserve(self.len, additional);
- }
-
- /// Reserves the minimum capacity for exactly `additional` more elements to
- /// be inserted in the given `Vec<T>`. After calling `reserve_exact`,
- /// capacity will be greater than or equal to `self.len() + additional`.
- /// Does nothing if the capacity is already sufficient.
- ///
- /// Note that the allocator may give the collection more space than it
- /// requests. Therefore, capacity can not be relied upon to be precisely
- /// minimal. Prefer `reserve` if future insertions are expected.
- ///
- /// # Panics
- ///
- /// Panics if the new capacity overflows `usize`.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1];
- /// vec.reserve_exact(10);
- /// assert!(vec.capacity() >= 11);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn reserve_exact(&mut self, additional: usize) {
- self.buf.reserve_exact(self.len, additional);
- }
-
- /// Tries to reserve capacity for at least `additional` more elements to be inserted
- /// in the given `Vec<T>`. The collection may reserve more space to avoid
- /// frequent reallocations. After calling `try_reserve`, capacity will be
- /// greater than or equal to `self.len() + additional`. Does nothing if
- /// capacity is already sufficient.
- ///
- /// # Errors
- ///
- /// If the capacity overflows, or the allocator reports a failure, then an error
- /// is returned.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(try_reserve)]
- /// use std::collections::TryReserveError;
- ///
- /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
- /// let mut output = Vec::new();
- ///
- /// // Pre-reserve the memory, exiting if we can't
- /// output.try_reserve(data.len())?;
- ///
- /// // Now we know this can't OOM in the middle of our complex work
- /// output.extend(data.iter().map(|&val| {
- /// val * 2 + 5 // very complicated
- /// }));
- ///
- /// Ok(output)
- /// }
- /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
- /// ```
- #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
- pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
- self.buf.try_reserve(self.len, additional)
- }
-
- /// Tries to reserve the minimum capacity for exactly `additional`
- /// elements to be inserted in the given `Vec<T>`. After calling
- /// `try_reserve_exact`, capacity will be greater than or equal to
- /// `self.len() + additional` if it returns `Ok(())`.
- /// Does nothing if the capacity is already sufficient.
- ///
- /// Note that the allocator may give the collection more space than it
- /// requests. Therefore, capacity can not be relied upon to be precisely
- /// minimal. Prefer `reserve` if future insertions are expected.
- ///
- /// # Errors
- ///
- /// If the capacity overflows, or the allocator reports a failure, then an error
- /// is returned.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(try_reserve)]
- /// use std::collections::TryReserveError;
- ///
- /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
- /// let mut output = Vec::new();
- ///
- /// // Pre-reserve the memory, exiting if we can't
- /// output.try_reserve_exact(data.len())?;
- ///
- /// // Now we know this can't OOM in the middle of our complex work
- /// output.extend(data.iter().map(|&val| {
- /// val * 2 + 5 // very complicated
- /// }));
- ///
- /// Ok(output)
- /// }
- /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
- /// ```
- #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
- pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
- self.buf.try_reserve_exact(self.len, additional)
- }
-
- /// Shrinks the capacity of the vector as much as possible.
- ///
- /// It will drop down as close as possible to the length but the allocator
- /// may still inform the vector that there is space for a few more elements.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
- /// assert_eq!(vec.capacity(), 10);
- /// vec.shrink_to_fit();
- /// assert!(vec.capacity() >= 3);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn shrink_to_fit(&mut self) {
- // The capacity is never less than the length, and there's nothing to do when
- // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit`
- // by only calling it with a greater capacity.
- if self.capacity() > self.len {
- self.buf.shrink_to_fit(self.len);
- }
- }
-
- /// Shrinks the capacity of the vector with a lower bound.
- ///
- /// The capacity will remain at least as large as both the length
- /// and the supplied value.
- ///
- /// # Panics
- ///
- /// Panics if the current capacity is smaller than the supplied
- /// minimum capacity.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(shrink_to)]
- /// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
- /// assert_eq!(vec.capacity(), 10);
- /// vec.shrink_to(4);
- /// assert!(vec.capacity() >= 4);
- /// vec.shrink_to(0);
- /// assert!(vec.capacity() >= 3);
- /// ```
- #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
- pub fn shrink_to(&mut self, min_capacity: usize) {
- self.buf.shrink_to_fit(cmp::max(self.len, min_capacity));
- }
-
- /// Converts the vector into [`Box<[T]>`][owned slice].
- ///
- /// Note that this will drop any excess capacity.
- ///
- /// [owned slice]: Box
- ///
- /// # Examples
- ///
- /// ```
- /// let v = vec![1, 2, 3];
- ///
- /// let slice = v.into_boxed_slice();
- /// ```
- ///
- /// Any excess capacity is removed:
- ///
- /// ```
- /// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
- ///
- /// assert_eq!(vec.capacity(), 10);
- /// let slice = vec.into_boxed_slice();
- /// assert_eq!(slice.into_vec().capacity(), 3);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn into_boxed_slice(mut self) -> Box<[T], A> {
- unsafe {
- self.shrink_to_fit();
- let me = ManuallyDrop::new(self);
- let buf = ptr::read(&me.buf);
- let len = me.len();
- buf.into_box(len).assume_init()
- }
- }
-
- /// Shortens the vector, keeping the first `len` elements and dropping
- /// the rest.
- ///
- /// If `len` is greater than the vector's current length, this has no
- /// effect.
- ///
- /// The [`drain`] method can emulate `truncate`, but causes the excess
- /// elements to be returned instead of dropped.
- ///
- /// Note that this method has no effect on the allocated capacity
- /// of the vector.
- ///
- /// # Examples
- ///
- /// Truncating a five element vector to two elements:
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3, 4, 5];
- /// vec.truncate(2);
- /// assert_eq!(vec, [1, 2]);
- /// ```
- ///
- /// No truncation occurs when `len` is greater than the vector's current
- /// length:
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3];
- /// vec.truncate(8);
- /// assert_eq!(vec, [1, 2, 3]);
- /// ```
- ///
- /// Truncating when `len == 0` is equivalent to calling the [`clear`]
- /// method.
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3];
- /// vec.truncate(0);
- /// assert_eq!(vec, []);
- /// ```
- ///
- /// [`clear`]: Vec::clear
- /// [`drain`]: Vec::drain
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn truncate(&mut self, len: usize) {
- // This is safe because:
- //
- // * the slice passed to `drop_in_place` is valid; the `len > self.len`
- // case avoids creating an invalid slice, and
- // * the `len` of the vector is shrunk before calling `drop_in_place`,
- // such that no value will be dropped twice in case `drop_in_place`
- // were to panic once (if it panics twice, the program aborts).
- unsafe {
- if len > self.len {
- return;
- }
- let remaining_len = self.len - len;
- let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len);
- self.len = len;
- ptr::drop_in_place(s);
- }
- }
-
- /// Extracts a slice containing the entire vector.
- ///
- /// Equivalent to `&s[..]`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::io::{self, Write};
- /// let buffer = vec![1, 2, 3, 5, 8];
- /// io::sink().write(buffer.as_slice()).unwrap();
- /// ```
- #[inline]
- #[stable(feature = "vec_as_slice", since = "1.7.0")]
- pub fn as_slice(&self) -> &[T] {
- self
- }
-
- /// Extracts a mutable slice of the entire vector.
- ///
- /// Equivalent to `&mut s[..]`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::io::{self, Read};
- /// let mut buffer = vec![0; 3];
- /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap();
- /// ```
- #[inline]
- #[stable(feature = "vec_as_slice", since = "1.7.0")]
- pub fn as_mut_slice(&mut self) -> &mut [T] {
- self
- }
-
- /// Returns a raw pointer to the vector's buffer.
- ///
- /// The caller must ensure that the vector outlives the pointer this
- /// function returns, or else it will end up pointing to garbage.
- /// Modifying the vector may cause its buffer to be reallocated,
- /// which would also make any pointers to it invalid.
- ///
- /// The caller must also ensure that the memory the pointer (non-transitively) points to
- /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
- /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
- ///
- /// # Examples
- ///
- /// ```
- /// let x = vec![1, 2, 4];
- /// let x_ptr = x.as_ptr();
- ///
- /// unsafe {
- /// for i in 0..x.len() {
- /// assert_eq!(*x_ptr.add(i), 1 << i);
- /// }
- /// }
- /// ```
- ///
- /// [`as_mut_ptr`]: Vec::as_mut_ptr
- #[stable(feature = "vec_as_ptr", since = "1.37.0")]
- #[inline]
- pub fn as_ptr(&self) -> *const T {
- // We shadow the slice method of the same name to avoid going through
- // `deref`, which creates an intermediate reference.
- let ptr = self.buf.ptr();
- unsafe {
- assume(!ptr.is_null());
- }
- ptr
- }
-
- /// Returns an unsafe mutable pointer to the vector's buffer.
- ///
- /// The caller must ensure that the vector outlives the pointer this
- /// function returns, or else it will end up pointing to garbage.
- /// Modifying the vector may cause its buffer to be reallocated,
- /// which would also make any pointers to it invalid.
- ///
- /// # Examples
- ///
- /// ```
- /// // Allocate vector big enough for 4 elements.
- /// let size = 4;
- /// let mut x: Vec<i32> = Vec::with_capacity(size);
- /// let x_ptr = x.as_mut_ptr();
- ///
- /// // Initialize elements via raw pointer writes, then set length.
- /// unsafe {
- /// for i in 0..size {
- /// *x_ptr.add(i) = i as i32;
- /// }
- /// x.set_len(size);
- /// }
- /// assert_eq!(&*x, &[0, 1, 2, 3]);
- /// ```
- #[stable(feature = "vec_as_ptr", since = "1.37.0")]
- #[inline]
- pub fn as_mut_ptr(&mut self) -> *mut T {
- // We shadow the slice method of the same name to avoid going through
- // `deref_mut`, which creates an intermediate reference.
- let ptr = self.buf.ptr();
- unsafe {
- assume(!ptr.is_null());
- }
- ptr
- }
-
- /// Returns a reference to the underlying allocator.
- #[unstable(feature = "allocator_api", issue = "32838")]
- #[inline]
- pub fn allocator(&self) -> &A {
- self.buf.allocator()
- }
-
- /// Forces the length of the vector to `new_len`.
- ///
- /// This is a low-level operation that maintains none of the normal
- /// invariants of the type. Normally changing the length of a vector
- /// is done using one of the safe operations instead, such as
- /// [`truncate`], [`resize`], [`extend`], or [`clear`].
- ///
- /// [`truncate`]: Vec::truncate
- /// [`resize`]: Vec::resize
- /// [`extend`]: Extend::extend
- /// [`clear`]: Vec::clear
- ///
- /// # Safety
- ///
- /// - `new_len` must be less than or equal to [`capacity()`].
- /// - The elements at `old_len..new_len` must be initialized.
- ///
- /// [`capacity()`]: Vec::capacity
- ///
- /// # Examples
- ///
- /// This method can be useful for situations in which the vector
- /// is serving as a buffer for other code, particularly over FFI:
- ///
- /// ```no_run
- /// # #![allow(dead_code)]
- /// # // This is just a minimal skeleton for the doc example;
- /// # // don't use this as a starting point for a real library.
- /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void }
- /// # const Z_OK: i32 = 0;
- /// # extern "C" {
- /// # fn deflateGetDictionary(
- /// # strm: *mut std::ffi::c_void,
- /// # dictionary: *mut u8,
- /// # dictLength: *mut usize,
- /// # ) -> i32;
- /// # }
- /// # impl StreamWrapper {
- /// pub fn get_dictionary(&self) -> Option<Vec<u8>> {
- /// // Per the FFI method's docs, "32768 bytes is always enough".
- /// let mut dict = Vec::with_capacity(32_768);
- /// let mut dict_length = 0;
- /// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that:
- /// // 1. `dict_length` elements were initialized.
- /// // 2. `dict_length` <= the capacity (32_768)
- /// // which makes `set_len` safe to call.
- /// unsafe {
- /// // Make the FFI call...
- /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length);
- /// if r == Z_OK {
- /// // ...and update the length to what was initialized.
- /// dict.set_len(dict_length);
- /// Some(dict)
- /// } else {
- /// None
- /// }
- /// }
- /// }
- /// # }
- /// ```
- ///
- /// While the following example is sound, there is a memory leak since
- /// the inner vectors were not freed prior to the `set_len` call:
- ///
- /// ```
- /// let mut vec = vec![vec![1, 0, 0],
- /// vec![0, 1, 0],
- /// vec![0, 0, 1]];
- /// // SAFETY:
- /// // 1. `old_len..0` is empty so no elements need to be initialized.
- /// // 2. `0 <= capacity` always holds whatever `capacity` is.
- /// unsafe {
- /// vec.set_len(0);
- /// }
- /// ```
- ///
- /// Normally, here, one would use [`clear`] instead to correctly drop
- /// the contents and thus not leak memory.
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn set_len(&mut self, new_len: usize) {
- debug_assert!(new_len <= self.capacity());
-
- self.len = new_len;
- }
-
- /// Removes an element from the vector and returns it.
- ///
- /// The removed element is replaced by the last element of the vector.
- ///
- /// This does not preserve ordering, but is O(1).
- ///
- /// # Panics
- ///
- /// Panics if `index` is out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = vec!["foo", "bar", "baz", "qux"];
- ///
- /// assert_eq!(v.swap_remove(1), "bar");
- /// assert_eq!(v, ["foo", "qux", "baz"]);
- ///
- /// assert_eq!(v.swap_remove(0), "foo");
- /// assert_eq!(v, ["baz", "qux"]);
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn swap_remove(&mut self, index: usize) -> T {
- #[cold]
- #[inline(never)]
- fn assert_failed(index: usize, len: usize) -> ! {
- panic!("swap_remove index (is {}) should be < len (is {})", index, len);
- }
-
- let len = self.len();
- if index >= len {
- assert_failed(index, len);
- }
- unsafe {
- // We replace self[index] with the last element. Note that if the
- // bounds check above succeeds there must be a last element (which
- // can be self[index] itself).
- let last = ptr::read(self.as_ptr().add(len - 1));
- let hole = self.as_mut_ptr().add(index);
- self.set_len(len - 1);
- ptr::replace(hole, last)
- }
- }
-
- /// Inserts an element at position `index` within the vector, shifting all
- /// elements after it to the right.
- ///
- /// # Panics
- ///
- /// Panics if `index > len`.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3];
- /// vec.insert(1, 4);
- /// assert_eq!(vec, [1, 4, 2, 3]);
- /// vec.insert(4, 5);
- /// assert_eq!(vec, [1, 4, 2, 3, 5]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn insert(&mut self, index: usize, element: T) {
- #[cold]
- #[inline(never)]
- fn assert_failed(index: usize, len: usize) -> ! {
- panic!("insertion index (is {}) should be <= len (is {})", index, len);
- }
-
- let len = self.len();
- if index > len {
- assert_failed(index, len);
- }
-
- // space for the new element
- if len == self.buf.capacity() {
- self.reserve(1);
- }
-
- unsafe {
- // infallible
- // The spot to put the new value
- {
- let p = self.as_mut_ptr().add(index);
- // Shift everything over to make space. (Duplicating the
- // `index`th element into two consecutive places.)
- ptr::copy(p, p.offset(1), len - index);
- // Write it in, overwriting the first copy of the `index`th
- // element.
- ptr::write(p, element);
- }
- self.set_len(len + 1);
- }
- }
-
- /// Removes and returns the element at position `index` within the vector,
- /// shifting all elements after it to the left.
- ///
- /// # Panics
- ///
- /// Panics if `index` is out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = vec![1, 2, 3];
- /// assert_eq!(v.remove(1), 2);
- /// assert_eq!(v, [1, 3]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn remove(&mut self, index: usize) -> T {
- #[cold]
- #[inline(never)]
- fn assert_failed(index: usize, len: usize) -> ! {
- panic!("removal index (is {}) should be < len (is {})", index, len);
- }
-
- let len = self.len();
- if index >= len {
- assert_failed(index, len);
- }
- unsafe {
- // infallible
- let ret;
- {
- // the place we are taking from.
- let ptr = self.as_mut_ptr().add(index);
- // copy it out, unsafely having a copy of the value on
- // the stack and in the vector at the same time.
- ret = ptr::read(ptr);
-
- // Shift everything down to fill in that spot.
- ptr::copy(ptr.offset(1), ptr, len - index - 1);
- }
- self.set_len(len - 1);
- ret
- }
- }
-
- /// Retains only the elements specified by the predicate.
- ///
- /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
- /// This method operates in place, visiting each element exactly once in the
- /// original order, and preserves the order of the retained elements.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3, 4];
- /// vec.retain(|&x| x % 2 == 0);
- /// assert_eq!(vec, [2, 4]);
- /// ```
- ///
- /// The exact order may be useful for tracking external state, like an index.
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3, 4, 5];
- /// let keep = [false, true, true, false, true];
- /// let mut i = 0;
- /// vec.retain(|_| (keep[i], i += 1).0);
- /// assert_eq!(vec, [2, 3, 5]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn retain<F>(&mut self, mut f: F)
- where
- F: FnMut(&T) -> bool,
- {
- let len = self.len();
- let mut del = 0;
- {
- let v = &mut **self;
-
- for i in 0..len {
- if !f(&v[i]) {
- del += 1;
- } else if del > 0 {
- v.swap(i - del, i);
- }
- }
- }
- if del > 0 {
- self.truncate(len - del);
- }
- }
-
- /// Removes all but the first of consecutive elements in the vector that resolve to the same
- /// key.
- ///
- /// If the vector is sorted, this removes all duplicates.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![10, 20, 21, 30, 20];
- ///
- /// vec.dedup_by_key(|i| *i / 10);
- ///
- /// assert_eq!(vec, [10, 20, 30, 20]);
- /// ```
- #[stable(feature = "dedup_by", since = "1.16.0")]
- #[inline]
- pub fn dedup_by_key<F, K>(&mut self, mut key: F)
- where
- F: FnMut(&mut T) -> K,
- K: PartialEq,
- {
- self.dedup_by(|a, b| key(a) == key(b))
- }
-
- /// Removes all but the first of consecutive elements in the vector satisfying a given equality
- /// relation.
- ///
- /// The `same_bucket` function is passed references to two elements from the vector and
- /// must determine if the elements compare equal. The elements are passed in opposite order
- /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
- ///
- /// If the vector is sorted, this removes all duplicates.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
- ///
- /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
- ///
- /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
- /// ```
- #[stable(feature = "dedup_by", since = "1.16.0")]
- pub fn dedup_by<F>(&mut self, same_bucket: F)
- where
- F: FnMut(&mut T, &mut T) -> bool,
- {
- let len = {
- let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
- dedup.len()
- };
- self.truncate(len);
- }
-
- /// Appends an element to the back of a collection.
- ///
- /// # Panics
- ///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2];
- /// vec.push(3);
- /// assert_eq!(vec, [1, 2, 3]);
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn push(&mut self, value: T) {
- // This will panic or abort if we would allocate > isize::MAX bytes
- // or if the length increment would overflow for zero-sized types.
- if self.len == self.buf.capacity() {
- self.reserve(1);
- }
- unsafe {
- let end = self.as_mut_ptr().add(self.len);
- ptr::write(end, value);
- self.len += 1;
- }
- }
-
- /// Removes the last element from a vector and returns it, or [`None`] if it
- /// is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3];
- /// assert_eq!(vec.pop(), Some(3));
- /// assert_eq!(vec, [1, 2]);
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn pop(&mut self) -> Option<T> {
- if self.len == 0 {
- None
- } else {
- unsafe {
- self.len -= 1;
- Some(ptr::read(self.as_ptr().add(self.len())))
- }
- }
- }
-
- /// Moves all the elements of `other` into `Self`, leaving `other` empty.
- ///
- /// # Panics
- ///
- /// Panics if the number of elements in the vector overflows a `usize`.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3];
- /// let mut vec2 = vec![4, 5, 6];
- /// vec.append(&mut vec2);
- /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
- /// assert_eq!(vec2, []);
- /// ```
- #[inline]
- #[stable(feature = "append", since = "1.4.0")]
- pub fn append(&mut self, other: &mut Self) {
- unsafe {
- self.append_elements(other.as_slice() as _);
- other.set_len(0);
- }
- }
-
- /// Appends elements to `Self` from other buffer.
- #[inline]
- unsafe fn append_elements(&mut self, other: *const [T]) {
- let count = unsafe { (*other).len() };
- self.reserve(count);
- let len = self.len();
- unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
- self.len += count;
- }
-
- /// Creates a draining iterator that removes the specified range in the vector
- /// and yields the removed items.
- ///
- /// When the iterator **is** dropped, all elements in the range are removed
- /// from the vector, even if the iterator was not fully consumed. If the
- /// iterator **is not** dropped (with [`mem::forget`] for example), it is
- /// unspecified how many elements are removed.
- ///
- /// # Panics
- ///
- /// Panics if the starting point is greater than the end point or if
- /// the end point is greater than the length of the vector.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = vec![1, 2, 3];
- /// let u: Vec<_> = v.drain(1..).collect();
- /// assert_eq!(v, &[1]);
- /// assert_eq!(u, &[2, 3]);
- ///
- /// // A full range clears the vector
- /// v.drain(..);
- /// assert_eq!(v, &[]);
- /// ```
- #[stable(feature = "drain", since = "1.6.0")]
- pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
- where
- R: RangeBounds<usize>,
- {
- // Memory safety
- //
- // When the Drain is first created, it shortens the length of
- // the source vector to make sure no uninitialized or moved-from elements
- // are accessible at all if the Drain's destructor never gets to run.
- //
- // Drain will ptr::read out the values to remove.
- // When finished, remaining tail of the vec is copied back to cover
- // the hole, and the vector length is restored to the new length.
- //
- let len = self.len();
- let Range { start, end } = range.assert_len(len);
-
- unsafe {
- // set self.vec length's to start, to be safe in case Drain is leaked
- self.set_len(start);
- // Use the borrow in the IterMut to indicate borrowing behavior of the
- // whole Drain iterator (like &mut T).
- let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start);
- Drain {
- tail_start: end,
- tail_len: len - end,
- iter: range_slice.iter(),
- vec: NonNull::from(self),
- }
- }
- }
-
- /// Clears the vector, removing all values.
- ///
- /// Note that this method has no effect on the allocated capacity
- /// of the vector.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = vec![1, 2, 3];
- ///
- /// v.clear();
- ///
- /// assert!(v.is_empty());
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn clear(&mut self) {
- self.truncate(0)
- }
-
- /// Returns the number of elements in the vector, also referred to
- /// as its 'length'.
- ///
- /// # Examples
- ///
- /// ```
- /// let a = vec![1, 2, 3];
- /// assert_eq!(a.len(), 3);
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn len(&self) -> usize {
- self.len
- }
-
- /// Returns `true` if the vector contains no elements.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = Vec::new();
- /// assert!(v.is_empty());
- ///
- /// v.push(1);
- /// assert!(!v.is_empty());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_empty(&self) -> bool {
- self.len() == 0
- }
-
- /// Splits the collection into two at the given index.
- ///
- /// Returns a newly allocated vector containing the elements in the range
- /// `[at, len)`. After the call, the original vector will be left containing
- /// the elements `[0, at)` with its previous capacity unchanged.
- ///
- /// # Panics
- ///
- /// Panics if `at > len`.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3];
- /// let vec2 = vec.split_off(1);
- /// assert_eq!(vec, [1]);
- /// assert_eq!(vec2, [2, 3]);
- /// ```
- #[inline]
- #[must_use = "use `.truncate()` if you don't need the other half"]
- #[stable(feature = "split_off", since = "1.4.0")]
- pub fn split_off(&mut self, at: usize) -> Self
- where
- A: Clone,
- {
- #[cold]
- #[inline(never)]
- fn assert_failed(at: usize, len: usize) -> ! {
- panic!("`at` split index (is {}) should be <= len (is {})", at, len);
- }
-
- if at > self.len() {
- assert_failed(at, self.len());
- }
-
- if at == 0 {
- // the new vector can take over the original buffer and avoid the copy
- return mem::replace(
- self,
- Vec::with_capacity_in(self.capacity(), self.allocator().clone()),
- );
- }
-
- let other_len = self.len - at;
- let mut other = Vec::with_capacity_in(other_len, self.allocator().clone());
-
- // Unsafely `set_len` and copy items to `other`.
- unsafe {
- self.set_len(at);
- other.set_len(other_len);
-
- ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other.len());
- }
- other
- }
-
- /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
- ///
- /// If `new_len` is greater than `len`, the `Vec` is extended by the
- /// difference, with each additional slot filled with the result of
- /// calling the closure `f`. The return values from `f` will end up
- /// in the `Vec` in the order they have been generated.
- ///
- /// If `new_len` is less than `len`, the `Vec` is simply truncated.
- ///
- /// This method uses a closure to create new values on every push. If
- /// you'd rather [`Clone`] a given value, use [`Vec::resize`]. If you
- /// want to use the [`Default`] trait to generate values, you can
- /// pass [`Default::default`] as the second argument.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2, 3];
- /// vec.resize_with(5, Default::default);
- /// assert_eq!(vec, [1, 2, 3, 0, 0]);
- ///
- /// let mut vec = vec![];
- /// let mut p = 1;
- /// vec.resize_with(4, || { p *= 2; p });
- /// assert_eq!(vec, [2, 4, 8, 16]);
- /// ```
- #[stable(feature = "vec_resize_with", since = "1.33.0")]
- pub fn resize_with<F>(&mut self, new_len: usize, f: F)
- where
- F: FnMut() -> T,
- {
- let len = self.len();
- if new_len > len {
- self.extend_with(new_len - len, ExtendFunc(f));
- } else {
- self.truncate(new_len);
- }
- }
-
- /// Consumes and leaks the `Vec`, returning a mutable reference to the contents,
- /// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime
- /// `'a`. If the type has only static references, or none at all, then this
- /// may be chosen to be `'static`.
- ///
- /// This function is similar to the [`leak`][Box::leak] function on [`Box`]
- /// except that there is no way to recover the leaked memory.
- ///
- /// This function is mainly useful for data that lives for the remainder of
- /// the program's life. Dropping the returned reference will cause a memory
- /// leak.
- ///
- /// # Examples
- ///
- /// Simple usage:
- ///
- /// ```
- /// let x = vec![1, 2, 3];
- /// let static_ref: &'static mut [usize] = x.leak();
- /// static_ref[0] += 1;
- /// assert_eq!(static_ref, &[2, 2, 3]);
- /// ```
- #[stable(feature = "vec_leak", since = "1.47.0")]
- #[inline]
- pub fn leak<'a>(self) -> &'a mut [T]
- where
- A: 'a,
- {
- Box::leak(self.into_boxed_slice())
- }
-
- /// Returns the remaining spare capacity of the vector as a slice of
- /// `MaybeUninit<T>`.
- ///
- /// The returned slice can be used to fill the vector with data (e.g. by
- /// reading from a file) before marking the data as initialized using the
- /// [`set_len`] method.
- ///
- /// [`set_len`]: Vec::set_len
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(vec_spare_capacity, maybe_uninit_extra)]
- ///
- /// // Allocate vector big enough for 10 elements.
- /// let mut v = Vec::with_capacity(10);
- ///
- /// // Fill in the first 3 elements.
- /// let uninit = v.spare_capacity_mut();
- /// uninit[0].write(0);
- /// uninit[1].write(1);
- /// uninit[2].write(2);
- ///
- /// // Mark the first 3 elements of the vector as being initialized.
- /// unsafe {
- /// v.set_len(3);
- /// }
- ///
- /// assert_eq!(&v, &[0, 1, 2]);
- /// ```
- #[unstable(feature = "vec_spare_capacity", issue = "75017")]
- #[inline]
- pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
- unsafe {
- slice::from_raw_parts_mut(
- self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
- self.buf.capacity() - self.len,
- )
- }
- }
-}
-
-impl<T: Clone, A: Allocator> Vec<T, A> {
- /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
- ///
- /// If `new_len` is greater than `len`, the `Vec` is extended by the
- /// difference, with each additional slot filled with `value`.
- /// If `new_len` is less than `len`, the `Vec` is simply truncated.
- ///
- /// This method requires `T` to implement [`Clone`],
- /// in order to be able to clone the passed value.
- /// If you need more flexibility (or want to rely on [`Default`] instead of
- /// [`Clone`]), use [`Vec::resize_with`].
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec!["hello"];
- /// vec.resize(3, "world");
- /// assert_eq!(vec, ["hello", "world", "world"]);
- ///
- /// let mut vec = vec![1, 2, 3, 4];
- /// vec.resize(2, 0);
- /// assert_eq!(vec, [1, 2]);
- /// ```
- #[stable(feature = "vec_resize", since = "1.5.0")]
- pub fn resize(&mut self, new_len: usize, value: T) {
- let len = self.len();
-
- if new_len > len {
- self.extend_with(new_len - len, ExtendElement(value))
- } else {
- self.truncate(new_len);
- }
- }
-
- /// Clones and appends all elements in a slice to the `Vec`.
- ///
- /// Iterates over the slice `other`, clones each element, and then appends
- /// it to this `Vec`. The `other` vector is traversed in-order.
- ///
- /// Note that this function is same as [`extend`] except that it is
- /// specialized to work with slices instead. If and when Rust gets
- /// specialization this function will likely be deprecated (but still
- /// available).
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1];
- /// vec.extend_from_slice(&[2, 3, 4]);
- /// assert_eq!(vec, [1, 2, 3, 4]);
- /// ```
- ///
- /// [`extend`]: Vec::extend
- #[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
- pub fn extend_from_slice(&mut self, other: &[T]) {
- self.spec_extend(other.iter())
- }
-}
-
-// This code generalizes `extend_with_{element,default}`.
-trait ExtendWith<T> {
- fn next(&mut self) -> T;
- fn last(self) -> T;
-}
-
-struct ExtendElement<T>(T);
-impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
- fn next(&mut self) -> T {
- self.0.clone()
- }
- fn last(self) -> T {
- self.0
- }
-}
-
-struct ExtendDefault;
-impl<T: Default> ExtendWith<T> for ExtendDefault {
- fn next(&mut self) -> T {
- Default::default()
- }
- fn last(self) -> T {
- Default::default()
- }
-}
-
-struct ExtendFunc<F>(F);
-impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
- fn next(&mut self) -> T {
- (self.0)()
- }
- fn last(mut self) -> T {
- (self.0)()
- }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
- /// Extend the vector by `n` values, using the given generator.
- fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
- self.reserve(n);
-
- unsafe {
- let mut ptr = self.as_mut_ptr().add(self.len());
- // Use SetLenOnDrop to work around bug where compiler
- // may not realize the store through `ptr` through self.set_len()
- // don't alias.
- let mut local_len = SetLenOnDrop::new(&mut self.len);
-
- // Write all elements except the last one
- for _ in 1..n {
- ptr::write(ptr, value.next());
- ptr = ptr.offset(1);
- // Increment the length in every step in case next() panics
- local_len.increment_len(1);
- }
-
- if n > 0 {
- // We can write the last element directly without cloning needlessly
- ptr::write(ptr, value.last());
- local_len.increment_len(1);
- }
-
- // len set by scope guard
- }
- }
-}
-
-// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
-//
-// The idea is: The length field in SetLenOnDrop is a local variable
-// that the optimizer will see does not alias with any stores through the Vec's data
-// pointer. This is a workaround for alias analysis issue #32155
-struct SetLenOnDrop<'a> {
- len: &'a mut usize,
- local_len: usize,
-}
-
-impl<'a> SetLenOnDrop<'a> {
- #[inline]
- fn new(len: &'a mut usize) -> Self {
- SetLenOnDrop { local_len: *len, len }
- }
-
- #[inline]
- fn increment_len(&mut self, increment: usize) {
- self.local_len += increment;
- }
-}
-
-impl Drop for SetLenOnDrop<'_> {
- #[inline]
- fn drop(&mut self) {
- *self.len = self.local_len;
- }
-}
-
-impl<T: PartialEq, A: Allocator> Vec<T, A> {
- /// Removes consecutive repeated elements in the vector according to the
- /// [`PartialEq`] trait implementation.
- ///
- /// If the vector is sorted, this removes all duplicates.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec![1, 2, 2, 3, 2];
- ///
- /// vec.dedup();
- ///
- /// assert_eq!(vec, [1, 2, 3, 2]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn dedup(&mut self) {
- self.dedup_by(|a, b| a == b)
- }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
- /// Removes the first instance of `item` from the vector if the item exists.
- ///
- /// This method will be removed soon.
- #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
- #[rustc_deprecated(
- reason = "Removing the first item equal to a needle is already easily possible \
- with iterators and the current Vec methods. Furthermore, having a method for \
- one particular case of removal (linear search, only the first item, no swap remove) \
- but not for others is inconsistent. This method will be removed soon.",
- since = "1.46.0"
- )]
- pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
- where
- T: PartialEq<V>,
- {
- let pos = self.iter().position(|x| *x == *item)?;
- Some(self.remove(pos))
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Internal methods and functions
-////////////////////////////////////////////////////////////////////////////////
-
-#[doc(hidden)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
- <T as SpecFromElem>::from_elem(elem, n, Global)
-}
-
-#[doc(hidden)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
- <T as SpecFromElem>::from_elem(elem, n, alloc)
-}
-
-// Specialization trait used for Vec::from_elem
-trait SpecFromElem: Sized {
- fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A>;
-}
-
-impl<T: Clone> SpecFromElem for T {
- default fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A> {
- let mut v = Vec::with_capacity_in(n, alloc);
- v.extend_with(n, ExtendElement(elem));
- v
- }
-}
-
-impl SpecFromElem for i8 {
- #[inline]
- fn from_elem<A: Allocator>(elem: i8, n: usize, alloc: A) -> Vec<i8, A> {
- if elem == 0 {
- return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
- }
- unsafe {
- let mut v = Vec::with_capacity_in(n, alloc);
- ptr::write_bytes(v.as_mut_ptr(), elem as u8, n);
- v.set_len(n);
- v
- }
- }
-}
-
-impl SpecFromElem for u8 {
- #[inline]
- fn from_elem<A: Allocator>(elem: u8, n: usize, alloc: A) -> Vec<u8, A> {
- if elem == 0 {
- return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
- }
- unsafe {
- let mut v = Vec::with_capacity_in(n, alloc);
- ptr::write_bytes(v.as_mut_ptr(), elem, n);
- v.set_len(n);
- v
- }
- }
-}
-
-impl<T: Clone + IsZero> SpecFromElem for T {
- #[inline]
- fn from_elem<A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
- if elem.is_zero() {
- return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
- }
- let mut v = Vec::with_capacity_in(n, alloc);
- v.extend_with(n, ExtendElement(elem));
- v
- }
-}
-
-#[rustc_specialization_trait]
-unsafe trait IsZero {
- /// Whether this value is zero
- fn is_zero(&self) -> bool;
-}
-
-macro_rules! impl_is_zero {
- ($t:ty, $is_zero:expr) => {
- unsafe impl IsZero for $t {
- #[inline]
- fn is_zero(&self) -> bool {
- $is_zero(*self)
- }
- }
- };
-}
-
-impl_is_zero!(i16, |x| x == 0);
-impl_is_zero!(i32, |x| x == 0);
-impl_is_zero!(i64, |x| x == 0);
-impl_is_zero!(i128, |x| x == 0);
-impl_is_zero!(isize, |x| x == 0);
-
-impl_is_zero!(u16, |x| x == 0);
-impl_is_zero!(u32, |x| x == 0);
-impl_is_zero!(u64, |x| x == 0);
-impl_is_zero!(u128, |x| x == 0);
-impl_is_zero!(usize, |x| x == 0);
-
-impl_is_zero!(bool, |x| x == false);
-impl_is_zero!(char, |x| x == '\0');
-
-impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
-impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
-
-unsafe impl<T> IsZero for *const T {
- #[inline]
- fn is_zero(&self) -> bool {
- (*self).is_null()
- }
-}
-
-unsafe impl<T> IsZero for *mut T {
- #[inline]
- fn is_zero(&self) -> bool {
- (*self).is_null()
- }
-}
-
-// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
-// For fat pointers, the bytes that would be the pointer metadata in the `Some`
-// variant are padding in the `None` variant, so ignoring them and
-// zero-initializing instead is ok.
-// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
-// `SpecFromElem`.
-
-unsafe impl<T: ?Sized> IsZero for Option<&T> {
- #[inline]
- fn is_zero(&self) -> bool {
- self.is_none()
- }
-}
-
-unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
- #[inline]
- fn is_zero(&self) -> bool {
- self.is_none()
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Common trait implementations for Vec
-////////////////////////////////////////////////////////////////////////////////
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> ops::Deref for Vec<T, A> {
- type Target = [T];
-
- fn deref(&self) -> &[T] {
- unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
- fn deref_mut(&mut self) -> &mut [T] {
- unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
- #[cfg(not(test))]
- fn clone(&self) -> Self {
- let alloc = self.allocator().clone();
- <[T]>::to_vec_in(&**self, alloc)
- }
-
- // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
- // required for this method definition, is not available. Instead use the
- // `slice::to_vec` function which is only available with cfg(test)
- // NB see the slice::hack module in slice.rs for more information
- #[cfg(test)]
- fn clone(&self) -> Self {
- let alloc = self.allocator().clone();
- crate::slice::to_vec(&**self, alloc)
- }
-
- fn clone_from(&mut self, other: &Self) {
- // drop anything that will not be overwritten
- self.truncate(other.len());
-
- // self.len <= other.len due to the truncate above, so the
- // slices here are always in-bounds.
- let (init, tail) = other.split_at(self.len());
-
- // reuse the contained values' allocations/resources.
- self.clone_from_slice(init);
- self.extend_from_slice(tail);
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- Hash::hash(&**self, state)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented(
- message = "vector indices are of type `usize` or ranges of `usize`",
- label = "vector indices are of type `usize` or ranges of `usize`"
-)]
-impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
- type Output = I::Output;
-
- #[inline]
- fn index(&self, index: I) -> &Self::Output {
- Index::index(&**self, index)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented(
- message = "vector indices are of type `usize` or ranges of `usize`",
- label = "vector indices are of type `usize` or ranges of `usize`"
-)]
-impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
- #[inline]
- fn index_mut(&mut self, index: I) -> &mut Self::Output {
- IndexMut::index_mut(&mut **self, index)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> FromIterator<T> for Vec<T> {
- #[inline]
- fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
- <Self as SpecFromIter<T, I::IntoIter>>::from_iter(iter.into_iter())
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> IntoIterator for Vec<T, A> {
- type Item = T;
- type IntoIter = IntoIter<T, A>;
-
- /// Creates a consuming iterator, that is, one that moves each value out of
- /// the vector (from start to end). The vector cannot be used after calling
- /// this.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = vec!["a".to_string(), "b".to_string()];
- /// for s in v.into_iter() {
- /// // s has type String, not &String
- /// println!("{}", s);
- /// }
- /// ```
- #[inline]
- fn into_iter(self) -> IntoIter<T, A> {
- unsafe {
- let mut me = ManuallyDrop::new(self);
- let alloc = ptr::read(me.allocator());
- let begin = me.as_mut_ptr();
- let end = if mem::size_of::<T>() == 0 {
- arith_offset(begin as *const i8, me.len() as isize) as *const T
- } else {
- begin.add(me.len()) as *const T
- };
- let cap = me.buf.capacity();
- IntoIter {
- buf: NonNull::new_unchecked(begin),
- phantom: PhantomData,
- cap,
- alloc,
- ptr: begin,
- end,
- }
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
- type Item = &'a T;
- type IntoIter = slice::Iter<'a, T>;
-
- fn into_iter(self) -> slice::Iter<'a, T> {
- self.iter()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
- type Item = &'a mut T;
- type IntoIter = slice::IterMut<'a, T>;
-
- fn into_iter(self) -> slice::IterMut<'a, T> {
- self.iter_mut()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> Extend<T> for Vec<T, A> {
- #[inline]
- fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
- <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
- }
-
- #[inline]
- fn extend_one(&mut self, item: T) {
- self.push(item);
- }
-
- #[inline]
- fn extend_reserve(&mut self, additional: usize) {
- self.reserve(additional);
- }
-}
-
-/// Specialization trait used for Vec::from_iter
-///
-/// ## The delegation graph:
-///
-/// ```text
-/// +-------------+
-/// |FromIterator |
-/// +-+-----------+
-/// |
-/// v
-/// +-+-------------------------------+ +---------------------+
-/// |SpecFromIter +---->+SpecFromIterNested |
-/// |where I: | | |where I: |
-/// | Iterator (default)----------+ | | Iterator (default) |
-/// | vec::IntoIter | | | TrustedLen |
-/// | SourceIterMarker---fallback-+ | | |
-/// | slice::Iter | | |
-/// | Iterator<Item = &Clone> | +---------------------+
-/// +---------------------------------+
-/// ```
-trait SpecFromIter<T, I> {
- fn from_iter(iter: I) -> Self;
-}
-
-/// Another specialization trait for Vec::from_iter
-/// necessary to manually prioritize overlapping specializations
-/// see [`SpecFromIter`] for details.
-trait SpecFromIterNested<T, I> {
- fn from_iter(iter: I) -> Self;
-}
-
-impl<T, I> SpecFromIterNested<T, I> for Vec<T>
-where
- I: Iterator<Item = T>,
-{
- default fn from_iter(mut iterator: I) -> Self {
- // Unroll the first iteration, as the vector is going to be
- // expanded on this iteration in every case when the iterable is not
- // empty, but the loop in extend_desugared() is not going to see the
- // vector being full in the few subsequent loop iterations.
- // So we get better branch prediction.
- let mut vector = match iterator.next() {
- None => return Vec::new(),
- Some(element) => {
- let (lower, _) = iterator.size_hint();
- let mut vector = Vec::with_capacity(lower.saturating_add(1));
- unsafe {
- ptr::write(vector.as_mut_ptr(), element);
- vector.set_len(1);
- }
- vector
- }
- };
- // must delegate to spec_extend() since extend() itself delegates
- // to spec_from for empty Vecs
- <Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
- vector
- }
-}
-
-impl<T, I> SpecFromIterNested<T, I> for Vec<T>
-where
- I: TrustedLen<Item = T>,
-{
- fn from_iter(iterator: I) -> Self {
- let mut vector = match iterator.size_hint() {
- (_, Some(upper)) => Vec::with_capacity(upper),
- _ => Vec::new(),
- };
- // must delegate to spec_extend() since extend() itself delegates
- // to spec_from for empty Vecs
- vector.spec_extend(iterator);
- vector
- }
-}
-
-impl<T, I> SpecFromIter<T, I> for Vec<T>
-where
- I: Iterator<Item = T>,
-{
- default fn from_iter(iterator: I) -> Self {
- SpecFromIterNested::from_iter(iterator)
- }
-}
-
-// A helper struct for in-place iteration that drops the destination slice of iteration,
-// i.e. the head. The source slice (the tail) is dropped by IntoIter.
-struct InPlaceDrop<T> {
- inner: *mut T,
- dst: *mut T,
-}
-
-impl<T> InPlaceDrop<T> {
- fn len(&self) -> usize {
- unsafe { self.dst.offset_from(self.inner) as usize }
- }
-}
-
-impl<T> Drop for InPlaceDrop<T> {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len()));
- }
- }
-}
-
-impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
- fn from_iter(iterator: IntoIter<T>) -> Self {
- // A common case is passing a vector into a function which immediately
- // re-collects into a vector. We can short circuit this if the IntoIter
- // has not been advanced at all.
- // When it has been advanced We can also reuse the memory and move the data to the front.
- // But we only do so when the resulting Vec wouldn't have more unused capacity
- // than creating it through the generic FromIterator implementation would. That limitation
- // is not strictly necessary as Vec's allocation behavior is intentionally unspecified.
- // But it is a conservative choice.
- let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr;
- if !has_advanced || iterator.len() >= iterator.cap / 2 {
- unsafe {
- let it = ManuallyDrop::new(iterator);
- if has_advanced {
- ptr::copy(it.ptr, it.buf.as_ptr(), it.len());
- }
- return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap);
- }
- }
-
- let mut vec = Vec::new();
- // must delegate to spec_extend() since extend() itself delegates
- // to spec_from for empty Vecs
- vec.spec_extend(iterator);
- vec
- }
-}
-
-fn write_in_place_with_drop<T>(
- src_end: *const T,
-) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
- move |mut sink, item| {
- unsafe {
- // the InPlaceIterable contract cannot be verified precisely here since
- // try_fold has an exclusive reference to the source pointer
- // all we can do is check if it's still in range
- debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
- ptr::write(sink.dst, item);
- sink.dst = sink.dst.add(1);
- }
- Ok(sink)
- }
-}
-
-/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
-/// source allocation, i.e. executing the pipeline in place.
-///
-/// The SourceIter parent trait is necessary for the specializing function to access the allocation
-/// which is to be reused. But it is not sufficient for the specialization to be valid. See
-/// additional bounds on the impl.
-#[rustc_unsafe_specialization_marker]
-trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
-
-// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
-// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
-// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
-// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
-// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
-// several other specializations already depend on.
-impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
-
-impl<T, I> SpecFromIter<T, I> for Vec<T>
-where
- I: Iterator<Item = T> + SourceIterMarker,
-{
- default fn from_iter(mut iterator: I) -> Self {
- // Additional requirements which cannot expressed via trait bounds. We rely on const eval
- // instead:
- // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
- // b) size match as required by Alloc contract
- // c) alignments match as required by Alloc contract
- if mem::size_of::<T>() == 0
- || mem::size_of::<T>()
- != mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
- || mem::align_of::<T>()
- != mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
- {
- // fallback to more generic implementations
- return SpecFromIterNested::from_iter(iterator);
- }
-
- let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
- let inner = iterator.as_inner().as_into_iter();
- (
- inner.buf.as_ptr(),
- inner.ptr,
- inner.buf.as_ptr() as *mut T,
- inner.end as *const T,
- inner.cap,
- )
- };
-
- // use try-fold since
- // - it vectorizes better for some iterator adapters
- // - unlike most internal iteration methods, it only takes a &mut self
- // - it lets us thread the write pointer through its innards and get it back in the end
- let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
- let sink = iterator
- .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
- .unwrap();
- // iteration succeeded, don't drop head
- let dst = ManuallyDrop::new(sink).dst;
-
- let src = unsafe { iterator.as_inner().as_into_iter() };
- // check if SourceIter contract was upheld
- // caveat: if they weren't we may not even make it to this point
- debug_assert_eq!(src_buf, src.buf.as_ptr());
- // check InPlaceIterable contract. This is only possible if the iterator advanced the
- // source pointer at all. If it uses unchecked access via TrustedRandomAccess
- // then the source pointer will stay in its initial position and we can't use it as reference
- if src.ptr != src_ptr {
- debug_assert!(
- dst as *const _ <= src.ptr,
- "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
- );
- }
-
- // drop any remaining values at the tail of the source
- src.drop_remaining();
- // but prevent drop of the allocation itself once IntoIter goes out of scope
- src.forget_allocation();
-
- let vec = unsafe {
- let len = dst.offset_from(dst_buf) as usize;
- Vec::from_raw_parts(dst_buf, len, cap)
- };
-
- vec
- }
-}
-
-impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
-where
- I: Iterator<Item = &'a T>,
- T: Clone,
-{
- default fn from_iter(iterator: I) -> Self {
- SpecFromIter::from_iter(iterator.cloned())
- }
-}
-
-// This utilizes `iterator.as_slice().to_vec()` since spec_extend
-// must take more steps to reason about the final capacity + length
-// and thus do more work. `to_vec()` directly allocates the correct amount
-// and fills it exactly.
-impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
- #[cfg(not(test))]
- fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
- iterator.as_slice().to_vec()
- }
-
- // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
- // required for this method definition, is not available. Instead use the
- // `slice::to_vec` function which is only available with cfg(test)
- // NB see the slice::hack module in slice.rs for more information
- #[cfg(test)]
- fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
- crate::slice::to_vec(iterator.as_slice(), Global)
- }
-}
-
-// Specialization trait used for Vec::extend
-trait SpecExtend<T, I> {
- fn spec_extend(&mut self, iter: I);
-}
-
-impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
-where
- I: Iterator<Item = T>,
-{
- default fn spec_extend(&mut self, iter: I) {
- self.extend_desugared(iter)
- }
-}
-
-impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
-where
- I: TrustedLen<Item = T>,
-{
- default fn spec_extend(&mut self, iterator: I) {
- // This is the case for a TrustedLen iterator.
- let (low, high) = iterator.size_hint();
- if let Some(high_value) = high {
- debug_assert_eq!(
- low,
- high_value,
- "TrustedLen iterator's size hint is not exact: {:?}",
- (low, high)
- );
- }
- if let Some(additional) = high {
- self.reserve(additional);
- unsafe {
- let mut ptr = self.as_mut_ptr().add(self.len());
- let mut local_len = SetLenOnDrop::new(&mut self.len);
- iterator.for_each(move |element| {
- ptr::write(ptr, element);
- ptr = ptr.offset(1);
- // NB can't overflow since we would have had to alloc the address space
- local_len.increment_len(1);
- });
- }
- } else {
- self.extend_desugared(iterator)
- }
- }
-}
-
-impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
- fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
- unsafe {
- self.append_elements(iterator.as_slice() as _);
- }
- iterator.ptr = iterator.end;
- }
-}
-
-impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
-where
- I: Iterator<Item = &'a T>,
- T: Clone,
-{
- default fn spec_extend(&mut self, iterator: I) {
- self.spec_extend(iterator.cloned())
- }
-}
-
-impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
-where
- T: Copy,
-{
- fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
- let slice = iterator.as_slice();
- unsafe { self.append_elements(slice) };
- }
-}
-
-impl<T, A: Allocator> Vec<T, A> {
- // leaf method to which various SpecFrom/SpecExtend implementations delegate when
- // they have no further optimizations to apply
- fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
- // This is the case for a general iterator.
- //
- // This function should be the moral equivalent of:
- //
- // for item in iterator {
- // self.push(item);
- // }
- while let Some(element) = iterator.next() {
- let len = self.len();
- if len == self.capacity() {
- let (lower, _) = iterator.size_hint();
- self.reserve(lower.saturating_add(1));
- }
- unsafe {
- ptr::write(self.as_mut_ptr().add(len), element);
- // NB can't overflow since we would have had to alloc the address space
- self.set_len(len + 1);
- }
- }
- }
-
- /// Creates a splicing iterator that replaces the specified range in the vector
- /// with the given `replace_with` iterator and yields the removed items.
- /// `replace_with` does not need to be the same length as `range`.
- ///
- /// `range` is removed even if the iterator is not consumed until the end.
- ///
- /// It is unspecified how many elements are removed from the vector
- /// if the `Splice` value is leaked.
- ///
- /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped.
- ///
- /// This is optimal if:
- ///
- /// * The tail (elements in the vector after `range`) is empty,
- /// * or `replace_with` yields fewer elements than `range`’s length
- /// * or the lower bound of its `size_hint()` is exact.
- ///
- /// Otherwise, a temporary vector is allocated and the tail is moved twice.
- ///
- /// # Panics
- ///
- /// Panics if the starting point is greater than the end point or if
- /// the end point is greater than the length of the vector.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = vec![1, 2, 3];
- /// let new = [7, 8];
- /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
- /// assert_eq!(v, &[7, 8, 3]);
- /// assert_eq!(u, &[1, 2]);
- /// ```
- #[inline]
- #[stable(feature = "vec_splice", since = "1.21.0")]
- pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
- where
- R: RangeBounds<usize>,
- I: IntoIterator<Item = T>,
- {
- Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
- }
-
- /// Creates an iterator which uses a closure to determine if an element should be removed.
- ///
- /// If the closure returns true, then the element is removed and yielded.
- /// If the closure returns false, the element will remain in the vector and will not be yielded
- /// by the iterator.
- ///
- /// Using this method is equivalent to the following code:
- ///
- /// ```
- /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
- /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
- /// let mut i = 0;
- /// while i != vec.len() {
- /// if some_predicate(&mut vec[i]) {
- /// let val = vec.remove(i);
- /// // your code here
- /// } else {
- /// i += 1;
- /// }
- /// }
- ///
- /// # assert_eq!(vec, vec![1, 4, 5]);
- /// ```
- ///
- /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
- /// because it can backshift the elements of the array in bulk.
- ///
- /// Note that `drain_filter` also lets you mutate every element in the filter closure,
- /// regardless of whether you choose to keep or remove it.
- ///
- /// # Examples
- ///
- /// Splitting an array into evens and odds, reusing the original allocation:
- ///
- /// ```
- /// #![feature(drain_filter)]
- /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
- ///
- /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
- /// let odds = numbers;
- ///
- /// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
- /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
- /// ```
- #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
- pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
- where
- F: FnMut(&mut T) -> bool,
- {
- let old_len = self.len();
-
- // Guard against us getting leaked (leak amplification)
- unsafe {
- self.set_len(0);
- }
-
- DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
- }
-}
-
-/// Extend implementation that copies elements out of references before pushing them onto the Vec.
-///
-/// This implementation is specialized for slice iterators, where it uses [`copy_from_slice`] to
-/// append the entire slice at once.
-///
-/// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice
-#[stable(feature = "extend_ref", since = "1.2.0")]
-impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
- fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
- self.spec_extend(iter.into_iter())
- }
-
- #[inline]
- fn extend_one(&mut self, &item: &'a T) {
- self.push(item);
- }
-
- #[inline]
- fn extend_reserve(&mut self, additional: usize) {
- self.reserve(additional);
- }
-}
-
-macro_rules! __impl_slice_eq1 {
- ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => {
- #[$stability]
- impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
- where
- T: PartialEq<U>,
- $($ty: $bound)?
- {
- #[inline]
- fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
- #[inline]
- fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
- }
- }
-}
-
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, Vec<U, A>, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
-__impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
-__impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
-__impl_slice_eq1! { [A: Allocator] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
-__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] }
-
-// NOTE: some less important impls are omitted to reduce code bloat
-// FIXME(Centril): Reconsider this?
-//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], }
-//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, }
-//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, }
-//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], }
-
-/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
- #[inline]
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- PartialOrd::partial_cmp(&**self, &**other)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq, A: Allocator> Eq for Vec<T, A> {}
-
-/// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord, A: Allocator> Ord for Vec<T, A> {
- #[inline]
- fn cmp(&self, other: &Self) -> Ordering {
- Ord::cmp(&**self, &**other)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
- fn drop(&mut self) {
- unsafe {
- // use drop for [T]
- // use a raw slice to refer to the elements of the vector as weakest necessary type;
- // could avoid questions of validity in certain cases
- ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len))
- }
- // RawVec handles deallocation
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Default for Vec<T> {
- /// Creates an empty `Vec<T>`.
- fn default() -> Vec<T> {
- Vec::new()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&**self, f)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> AsRef<Vec<T, A>> for Vec<T, A> {
- fn as_ref(&self) -> &Vec<T, A> {
- self
- }
-}
-
-#[stable(feature = "vec_as_mut", since = "1.5.0")]
-impl<T, A: Allocator> AsMut<Vec<T, A>> for Vec<T, A> {
- fn as_mut(&mut self) -> &mut Vec<T, A> {
- self
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> AsRef<[T]> for Vec<T, A> {
- fn as_ref(&self) -> &[T] {
- self
- }
-}
-
-#[stable(feature = "vec_as_mut", since = "1.5.0")]
-impl<T, A: Allocator> AsMut<[T]> for Vec<T, A> {
- fn as_mut(&mut self) -> &mut [T] {
- self
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> From<&[T]> for Vec<T> {
- #[cfg(not(test))]
- fn from(s: &[T]) -> Vec<T> {
- s.to_vec()
- }
- #[cfg(test)]
- fn from(s: &[T]) -> Vec<T> {
- crate::slice::to_vec(s, Global)
- }
-}
-
-#[stable(feature = "vec_from_mut", since = "1.19.0")]
-impl<T: Clone> From<&mut [T]> for Vec<T> {
- #[cfg(not(test))]
- fn from(s: &mut [T]) -> Vec<T> {
- s.to_vec()
- }
- #[cfg(test)]
- fn from(s: &mut [T]) -> Vec<T> {
- crate::slice::to_vec(s, Global)
- }
-}
-
-#[stable(feature = "vec_from_array", since = "1.44.0")]
-impl<T, const N: usize> From<[T; N]> for Vec<T> {
- #[cfg(not(test))]
- fn from(s: [T; N]) -> Vec<T> {
- <[T]>::into_vec(box s)
- }
- #[cfg(test)]
- fn from(s: [T; N]) -> Vec<T> {
- crate::slice::into_vec(box s)
- }
-}
-
-#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
-impl<'a, T> From<Cow<'a, [T]>> for Vec<T>
-where
- [T]: ToOwned<Owned = Vec<T>>,
-{
- fn from(s: Cow<'a, [T]>) -> Vec<T> {
- s.into_owned()
- }
-}
-
-// note: test pulls in libstd, which causes errors here
-#[cfg(not(test))]
-#[stable(feature = "vec_from_box", since = "1.18.0")]
-impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
- fn from(s: Box<[T], A>) -> Self {
- let len = s.len();
- Self { buf: RawVec::from_box(s), len }
- }
-}
-
-// note: test pulls in libstd, which causes errors here
-#[cfg(not(test))]
-#[stable(feature = "box_from_vec", since = "1.20.0")]
-impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
- fn from(v: Vec<T, A>) -> Self {
- v.into_boxed_slice()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl From<&str> for Vec<u8> {
- fn from(s: &str) -> Vec<u8> {
- From::from(s.as_bytes())
- }
-}
-
-#[stable(feature = "array_try_from_vec", since = "1.48.0")]
-impl<T, A: Allocator, const N: usize> TryFrom<Vec<T, A>> for [T; N] {
- type Error = Vec<T, A>;
-
- /// Gets the entire contents of the `Vec<T>` as an array,
- /// if its size exactly matches that of the requested array.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::convert::TryInto;
- /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
- /// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
- /// ```
- ///
- /// If the length doesn't match, the input comes back in `Err`:
- /// ```
- /// use std::convert::TryInto;
- /// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
- /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
- /// ```
- ///
- /// If you're fine with just getting a prefix of the `Vec<T>`,
- /// you can call [`.truncate(N)`](Vec::truncate) first.
- /// ```
- /// use std::convert::TryInto;
- /// let mut v = String::from("hello world").into_bytes();
- /// v.sort();
- /// v.truncate(2);
- /// let [a, b]: [_; 2] = v.try_into().unwrap();
- /// assert_eq!(a, b' ');
- /// assert_eq!(b, b'd');
- /// ```
- fn try_from(mut vec: Vec<T, A>) -> Result<[T; N], Vec<T, A>> {
- if vec.len() != N {
- return Err(vec);
- }
-
- // SAFETY: `.set_len(0)` is always sound.
- unsafe { vec.set_len(0) };
-
- // SAFETY: A `Vec`'s pointer is always aligned properly, and
- // the alignment the array needs is the same as the items.
- // We checked earlier that we have sufficient items.
- // The items will not double-drop as the `set_len`
- // tells the `Vec` not to also drop them.
- let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) };
- Ok(array)
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Clone-on-write
-////////////////////////////////////////////////////////////////////////////////
-
-#[stable(feature = "cow_from_vec", since = "1.8.0")]
-impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
- fn from(s: &'a [T]) -> Cow<'a, [T]> {
- Cow::Borrowed(s)
- }
-}
-
-#[stable(feature = "cow_from_vec", since = "1.8.0")]
-impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
- fn from(v: Vec<T>) -> Cow<'a, [T]> {
- Cow::Owned(v)
- }
-}
-
-#[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
-impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
- fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
- Cow::Borrowed(v.as_slice())
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> FromIterator<T> for Cow<'a, [T]>
-where
- T: Clone,
-{
- fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Cow<'a, [T]> {
- Cow::Owned(FromIterator::from_iter(it))
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Iterators
-////////////////////////////////////////////////////////////////////////////////
-
-/// An iterator that moves out of a vector.
-///
-/// This `struct` is created by the `into_iter` method on [`Vec`] (provided
-/// by the [`IntoIterator`] trait).
-///
-/// # Example
-///
-/// ```
-/// let v = vec![0, 1, 2];
-/// let iter: std::vec::IntoIter<_> = v.into_iter();
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IntoIter<
- T,
- #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-> {
- buf: NonNull<T>,
- phantom: PhantomData<T>,
- cap: usize,
- alloc: A,
- ptr: *const T,
- end: *const T,
-}
-
-#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
-impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
- }
-}
-
-impl<T, A: Allocator> IntoIter<T, A> {
- /// Returns the remaining items of this iterator as a slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let vec = vec!['a', 'b', 'c'];
- /// let mut into_iter = vec.into_iter();
- /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
- /// let _ = into_iter.next().unwrap();
- /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
- /// ```
- #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
- pub fn as_slice(&self) -> &[T] {
- unsafe { slice::from_raw_parts(self.ptr, self.len()) }
- }
-
- /// Returns the remaining items of this iterator as a mutable slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let vec = vec!['a', 'b', 'c'];
- /// let mut into_iter = vec.into_iter();
- /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
- /// into_iter.as_mut_slice()[2] = 'z';
- /// assert_eq!(into_iter.next().unwrap(), 'a');
- /// assert_eq!(into_iter.next().unwrap(), 'b');
- /// assert_eq!(into_iter.next().unwrap(), 'z');
- /// ```
- #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
- pub fn as_mut_slice(&mut self) -> &mut [T] {
- unsafe { &mut *self.as_raw_mut_slice() }
- }
-
- /// Returns a reference to the underlying allocator.
- #[unstable(feature = "allocator_api", issue = "32838")]
- #[inline]
- pub fn allocator(&self) -> &A {
- &self.alloc
- }
-
- fn as_raw_mut_slice(&mut self) -> *mut [T] {
- ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
- }
-
- fn drop_remaining(&mut self) {
- unsafe {
- ptr::drop_in_place(self.as_mut_slice());
- }
- self.ptr = self.end;
- }
-
- /// Relinquishes the backing allocation, equivalent to
- /// `ptr::write(&mut self, Vec::new().into_iter())`
- fn forget_allocation(&mut self) {
- self.cap = 0;
- self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) };
- self.ptr = self.buf.as_ptr();
- self.end = self.buf.as_ptr();
- }
-}
-
-#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
-impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> {
- fn as_ref(&self) -> &[T] {
- self.as_slice()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync, A: Allocator> Sync for IntoIter<T, A> {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> Iterator for IntoIter<T, A> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- if self.ptr as *const _ == self.end {
- None
- } else if mem::size_of::<T>() == 0 {
- // purposefully don't use 'ptr.offset' because for
- // vectors with 0-size elements this would return the
- // same pointer.
- self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
-
- // Make up a value of this ZST.
- Some(unsafe { mem::zeroed() })
- } else {
- let old = self.ptr;
- self.ptr = unsafe { self.ptr.offset(1) };
-
- Some(unsafe { ptr::read(old) })
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let exact = if mem::size_of::<T>() == 0 {
- (self.end as usize).wrapping_sub(self.ptr as usize)
- } else {
- unsafe { self.end.offset_from(self.ptr) as usize }
- };
- (exact, Some(exact))
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
- where
- Self: TrustedRandomAccess,
- {
- // SAFETY: the caller must guarantee that `i` is in bounds of the
- // `Vec<T>`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)`
- // is guaranteed to pointer to an element of the `Vec<T>` and
- // thus guaranteed to be valid to dereference.
- //
- // Also note the implementation of `Self: TrustedRandomAccess` requires
- // that `T: Copy` so reading elements from the buffer doesn't invalidate
- // them for `Drop`.
- unsafe {
- if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
- #[inline]
- fn next_back(&mut self) -> Option<T> {
- if self.end == self.ptr {
- None
- } else if mem::size_of::<T>() == 0 {
- // See above for why 'ptr.offset' isn't used
- self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T };
-
- // Make up a value of this ZST.
- Some(unsafe { mem::zeroed() })
- } else {
- self.end = unsafe { self.end.offset(-1) };
-
- Some(unsafe { ptr::read(self.end) })
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
- fn is_empty(&self) -> bool {
- self.ptr == self.end
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
-
-#[doc(hidden)]
-#[unstable(issue = "none", feature = "std_internals")]
-// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
-// and thus we can't implement drop-handling
-unsafe impl<T, A: Allocator> TrustedRandomAccess for IntoIter<T, A>
-where
- T: Copy,
-{
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
-impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
- #[cfg(not(test))]
- fn clone(&self) -> Self {
- self.as_slice().to_vec_in(self.alloc.clone()).into_iter()
- }
- #[cfg(test)]
- fn clone(&self) -> Self {
- crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
- fn drop(&mut self) {
- struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>);
-
- impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
- fn drop(&mut self) {
- unsafe {
- // `IntoIter::alloc` is not used anymore after this
- let alloc = ptr::read(&self.0.alloc);
- // RawVec handles deallocation
- let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc);
- }
- }
- }
-
- let guard = DropGuard(self);
- // destroy the remaining elements
- unsafe {
- ptr::drop_in_place(guard.0.as_raw_mut_slice());
- }
- // now `guard` will be dropped and do the rest
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
- type Source = Self;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut Self::Source {
- self
- }
-}
-
-// internal helper trait for in-place iteration specialization.
-#[rustc_specialization_trait]
-pub(crate) trait AsIntoIter {
- type Item;
- fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item>;
-}
-
-impl<T> AsIntoIter for IntoIter<T> {
- type Item = T;
-
- fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
- self
- }
-}
-
-/// A draining iterator for `Vec<T>`.
-///
-/// This `struct` is created by [`Vec::drain`].
-/// See its documentation for more.
-///
-/// # Example
-///
-/// ```
-/// let mut v = vec![0, 1, 2];
-/// let iter: std::vec::Drain<_> = v.drain(..);
-/// ```
-#[stable(feature = "drain", since = "1.6.0")]
-pub struct Drain<
- 'a,
- T: 'a,
- #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
-> {
- /// Index of tail to preserve
- tail_start: usize,
- /// Length of tail
- tail_len: usize,
- /// Current remaining range to remove
- iter: slice::Iter<'a, T>,
- vec: NonNull<Vec<T, A>>,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
- }
-}
-
-impl<'a, T, A: Allocator> Drain<'a, T, A> {
- /// Returns the remaining items of this iterator as a slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut vec = vec!['a', 'b', 'c'];
- /// let mut drain = vec.drain(..);
- /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
- /// let _ = drain.next().unwrap();
- /// assert_eq!(drain.as_slice(), &['b', 'c']);
- /// ```
- #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
- pub fn as_slice(&self) -> &[T] {
- self.iter.as_slice()
- }
-
- /// Returns a reference to the underlying allocator.
- #[unstable(feature = "allocator_api", issue = "32838")]
- #[inline]
- pub fn allocator(&self) -> &A {
- unsafe { self.vec.as_ref().allocator() }
- }
-}
-
-#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
-impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> {
- fn as_ref(&self) -> &[T] {
- self.as_slice()
- }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {}
-#[stable(feature = "drain", since = "1.6.0")]
-unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) })
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
- #[inline]
- fn next_back(&mut self) -> Option<T> {
- self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) })
- }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> Drop for Drain<'_, T, A> {
- fn drop(&mut self) {
- /// Continues dropping the remaining elements in the `Drain`, then moves back the
- /// un-`Drain`ed elements to restore the original `Vec`.
- struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
-
- impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
- fn drop(&mut self) {
- // Continue the same loop we have below. If the loop already finished, this does
- // nothing.
- self.0.for_each(drop);
-
- if self.0.tail_len > 0 {
- unsafe {
- let source_vec = self.0.vec.as_mut();
- // memmove back untouched tail, update to new length
- let start = source_vec.len();
- let tail = self.0.tail_start;
- if tail != start {
- let src = source_vec.as_ptr().add(tail);
- let dst = source_vec.as_mut_ptr().add(start);
- ptr::copy(src, dst, self.0.tail_len);
- }
- source_vec.set_len(start + self.0.tail_len);
- }
- }
- }
- }
-
- // exhaust self first
- while let Some(item) = self.next() {
- let guard = DropGuard(self);
- drop(item);
- mem::forget(guard);
- }
-
- // Drop a `DropGuard` to move back the non-drained tail of `self`.
- DropGuard(self);
- }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
-
-/// A splicing iterator for `Vec`.
-///
-/// This struct is created by [`Vec::splice()`].
-/// See its documentation for more.
-///
-/// # Example
-///
-/// ```
-/// let mut v = vec![0, 1, 2];
-/// let new = [7, 8];
-/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
-/// ```
-#[derive(Debug)]
-#[stable(feature = "vec_splice", since = "1.21.0")]
-pub struct Splice<
- 'a,
- I: Iterator + 'a,
- #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
-> {
- drain: Drain<'a, I::Item, A>,
- replace_with: I,
-}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
- type Item = I::Item;
-
- fn next(&mut self) -> Option<Self::Item> {
- self.drain.next()
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.drain.size_hint()
- }
-}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
- fn next_back(&mut self) -> Option<Self::Item> {
- self.drain.next_back()
- }
-}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
-
-#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
- fn drop(&mut self) {
- self.drain.by_ref().for_each(drop);
-
- unsafe {
- if self.drain.tail_len == 0 {
- self.drain.vec.as_mut().extend(self.replace_with.by_ref());
- return;
- }
-
- // First fill the range left by drain().
- if !self.drain.fill(&mut self.replace_with) {
- return;
- }
-
- // There may be more elements. Use the lower bound as an estimate.
- // FIXME: Is the upper bound a better guess? Or something else?
- let (lower_bound, _upper_bound) = self.replace_with.size_hint();
- if lower_bound > 0 {
- self.drain.move_tail(lower_bound);
- if !self.drain.fill(&mut self.replace_with) {
- return;
- }
- }
-
- // Collect any remaining elements.
- // This is a zero-length vector which does not allocate if `lower_bound` was exact.
- let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
- // Now we have an exact count.
- if collected.len() > 0 {
- self.drain.move_tail(collected.len());
- let filled = self.drain.fill(&mut collected);
- debug_assert!(filled);
- debug_assert_eq!(collected.len(), 0);
- }
- }
- // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
- }
-}
-
-/// Private helper methods for `Splice::drop`
-impl<T, A: Allocator> Drain<'_, T, A> {
- /// The range from `self.vec.len` to `self.tail_start` contains elements
- /// that have been moved out.
- /// Fill that range as much as possible with new elements from the `replace_with` iterator.
- /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
- unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
- let vec = unsafe { self.vec.as_mut() };
- let range_start = vec.len;
- let range_end = self.tail_start;
- let range_slice = unsafe {
- slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
- };
-
- for place in range_slice {
- if let Some(new_item) = replace_with.next() {
- unsafe { ptr::write(place, new_item) };
- vec.len += 1;
- } else {
- return false;
- }
- }
- true
- }
-
- /// Makes room for inserting more elements before the tail.
- unsafe fn move_tail(&mut self, additional: usize) {
- let vec = unsafe { self.vec.as_mut() };
- let len = self.tail_start + self.tail_len;
- vec.buf.reserve(len, additional);
-
- let new_tail_start = self.tail_start + additional;
- unsafe {
- let src = vec.as_ptr().add(self.tail_start);
- let dst = vec.as_mut_ptr().add(new_tail_start);
- ptr::copy(src, dst, self.tail_len);
- }
- self.tail_start = new_tail_start;
- }
-}
-
-/// An iterator which uses a closure to determine if an element should be removed.
-///
-/// This struct is created by [`Vec::drain_filter`].
-/// See its documentation for more.
-///
-/// # Example
-///
-/// ```
-/// #![feature(drain_filter)]
-///
-/// let mut v = vec![0, 1, 2];
-/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0);
-/// ```
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-#[derive(Debug)]
-pub struct DrainFilter<
- 'a,
- T,
- F,
- #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-> where
- F: FnMut(&mut T) -> bool,
-{
- vec: &'a mut Vec<T, A>,
- /// The index of the item that will be inspected by the next call to `next`.
- idx: usize,
- /// The number of items that have been drained (removed) thus far.
- del: usize,
- /// The original length of `vec` prior to draining.
- old_len: usize,
- /// The filter test predicate.
- pred: F,
- /// A flag that indicates a panic has occurred in the filter test predicate.
- /// This is used as a hint in the drop implementation to prevent consumption
- /// of the remainder of the `DrainFilter`. Any unprocessed items will be
- /// backshifted in the `vec`, but no further items will be dropped or
- /// tested by the filter predicate.
- panic_flag: bool,
-}
-
-impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
-where
- F: FnMut(&mut T) -> bool,
-{
- /// Returns a reference to the underlying allocator.
- #[unstable(feature = "allocator_api", issue = "32838")]
- #[inline]
- pub fn allocator(&self) -> &A {
- self.vec.allocator()
- }
-}
-
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
-where
- F: FnMut(&mut T) -> bool,
-{
- type Item = T;
-
- fn next(&mut self) -> Option<T> {
- unsafe {
- while self.idx < self.old_len {
- let i = self.idx;
- let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
- self.panic_flag = true;
- let drained = (self.pred)(&mut v[i]);
- self.panic_flag = false;
- // Update the index *after* the predicate is called. If the index
- // is updated prior and the predicate panics, the element at this
- // index would be leaked.
- self.idx += 1;
- if drained {
- self.del += 1;
- return Some(ptr::read(&v[i]));
- } else if self.del > 0 {
- let del = self.del;
- let src: *const T = &v[i];
- let dst: *mut T = &mut v[i - del];
- ptr::copy_nonoverlapping(src, dst, 1);
- }
- }
- None
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- (0, Some(self.old_len - self.idx))
- }
-}
-
-#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
-where
- F: FnMut(&mut T) -> bool,
-{
- fn drop(&mut self) {
- struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
- where
- F: FnMut(&mut T) -> bool,
- {
- drain: &'b mut DrainFilter<'a, T, F, A>,
- }
-
- impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
- where
- F: FnMut(&mut T) -> bool,
- {
- fn drop(&mut self) {
- unsafe {
- if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
- // This is a pretty messed up state, and there isn't really an
- // obviously right thing to do. We don't want to keep trying
- // to execute `pred`, so we just backshift all the unprocessed
- // elements and tell the vec that they still exist. The backshift
- // is required to prevent a double-drop of the last successfully
- // drained item prior to a panic in the predicate.
- let ptr = self.drain.vec.as_mut_ptr();
- let src = ptr.add(self.drain.idx);
- let dst = src.sub(self.drain.del);
- let tail_len = self.drain.old_len - self.drain.idx;
- src.copy_to(dst, tail_len);
- }
- self.drain.vec.set_len(self.drain.old_len - self.drain.del);
- }
- }
- }
-
- let backshift = BackshiftOnDrop { drain: self };
-
- // Attempt to consume any remaining elements if the filter predicate
- // has not yet panicked. We'll backshift any remaining elements
- // whether we've already panicked or if the consumption here panics.
- if !backshift.drain.panic_flag {
- backshift.drain.for_each(drop);
- }
- }
-}
--- /dev/null
+use crate::borrow::Cow;
+use core::iter::FromIterator;
+
+use super::Vec;
+
+#[stable(feature = "cow_from_vec", since = "1.8.0")]
+impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
+ fn from(s: &'a [T]) -> Cow<'a, [T]> {
+ Cow::Borrowed(s)
+ }
+}
+
+#[stable(feature = "cow_from_vec", since = "1.8.0")]
+impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
+ fn from(v: Vec<T>) -> Cow<'a, [T]> {
+ Cow::Owned(v)
+ }
+}
+
+#[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
+impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
+ fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
+ Cow::Borrowed(v.as_slice())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> FromIterator<T> for Cow<'a, [T]>
+where
+ T: Clone,
+{
+ fn from_iter<I: IntoIterator<Item = T>>(it: I) -> Cow<'a, [T]> {
+ Cow::Owned(FromIterator::from_iter(it))
+ }
+}
--- /dev/null
+use crate::alloc::{Allocator, Global};
+use core::fmt;
+use core::iter::{FusedIterator, TrustedLen};
+use core::mem::{self};
+use core::ptr::{self, NonNull};
+use core::slice::{self};
+
+use super::Vec;
+
+/// A draining iterator for `Vec<T>`.
+///
+/// This `struct` is created by [`Vec::drain`].
+/// See its documentation for more.
+///
+/// # Example
+///
+/// ```
+/// let mut v = vec![0, 1, 2];
+/// let iter: std::vec::Drain<_> = v.drain(..);
+/// ```
+#[stable(feature = "drain", since = "1.6.0")]
+pub struct Drain<
+ 'a,
+ T: 'a,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
+> {
+ /// Index of tail to preserve
+ pub(super) tail_start: usize,
+ /// Length of tail
+ pub(super) tail_len: usize,
+ /// Current remaining range to remove
+ pub(super) iter: slice::Iter<'a, T>,
+ pub(super) vec: NonNull<Vec<T, A>>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
+ }
+}
+
+impl<'a, T, A: Allocator> Drain<'a, T, A> {
+ /// Returns the remaining items of this iterator as a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec!['a', 'b', 'c'];
+ /// let mut drain = vec.drain(..);
+ /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
+ /// let _ = drain.next().unwrap();
+ /// assert_eq!(drain.as_slice(), &['b', 'c']);
+ /// ```
+ #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
+ pub fn as_slice(&self) -> &[T] {
+ self.iter.as_slice()
+ }
+
+ /// Returns a reference to the underlying allocator.
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ #[inline]
+ pub fn allocator(&self) -> &A {
+ unsafe { self.vec.as_ref().allocator() }
+ }
+}
+
+#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
+impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> {
+ fn as_ref(&self) -> &[T] {
+ self.as_slice()
+ }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {}
+#[stable(feature = "drain", since = "1.6.0")]
+unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> {
+ self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) })
+ }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> Drop for Drain<'_, T, A> {
+ fn drop(&mut self) {
+ /// Continues dropping the remaining elements in the `Drain`, then moves back the
+ /// un-`Drain`ed elements to restore the original `Vec`.
+ struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
+
+ impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
+ fn drop(&mut self) {
+ // Continue the same loop we have below. If the loop already finished, this does
+ // nothing.
+ self.0.for_each(drop);
+
+ if self.0.tail_len > 0 {
+ unsafe {
+ let source_vec = self.0.vec.as_mut();
+ // memmove back untouched tail, update to new length
+ let start = source_vec.len();
+ let tail = self.0.tail_start;
+ if tail != start {
+ let src = source_vec.as_ptr().add(tail);
+ let dst = source_vec.as_mut_ptr().add(start);
+ ptr::copy(src, dst, self.0.tail_len);
+ }
+ source_vec.set_len(start + self.0.tail_len);
+ }
+ }
+ }
+ }
+
+ // exhaust self first
+ while let Some(item) = self.next() {
+ let guard = DropGuard(self);
+ drop(item);
+ mem::forget(guard);
+ }
+
+ // Drop a `DropGuard` to move back the non-drained tail of `self`.
+ DropGuard(self);
+ }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
--- /dev/null
+use crate::alloc::{Allocator, Global};
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::Vec;
+
+/// An iterator which uses a closure to determine if an element should be removed.
+///
+/// This struct is created by [`Vec::drain_filter`].
+/// See its documentation for more.
+///
+/// # Example
+///
+/// ```
+/// #![feature(drain_filter)]
+///
+/// let mut v = vec![0, 1, 2];
+/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0);
+/// ```
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+#[derive(Debug)]
+pub struct DrainFilter<
+ 'a,
+ T,
+ F,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> where
+ F: FnMut(&mut T) -> bool,
+{
+ pub(super) vec: &'a mut Vec<T, A>,
+ /// The index of the item that will be inspected by the next call to `next`.
+ pub(super) idx: usize,
+ /// The number of items that have been drained (removed) thus far.
+ pub(super) del: usize,
+ /// The original length of `vec` prior to draining.
+ pub(super) old_len: usize,
+ /// The filter test predicate.
+ pub(super) pred: F,
+ /// A flag that indicates a panic has occurred in the filter test predicate.
+ /// This is used as a hint in the drop implementation to prevent consumption
+ /// of the remainder of the `DrainFilter`. Any unprocessed items will be
+ /// backshifted in the `vec`, but no further items will be dropped or
+ /// tested by the filter predicate.
+ pub(super) panic_flag: bool,
+}
+
+impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
+where
+ F: FnMut(&mut T) -> bool,
+{
+ /// Returns a reference to the underlying allocator.
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ #[inline]
+ pub fn allocator(&self) -> &A {
+ self.vec.allocator()
+ }
+}
+
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
+where
+ F: FnMut(&mut T) -> bool,
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ unsafe {
+ while self.idx < self.old_len {
+ let i = self.idx;
+ let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
+ self.panic_flag = true;
+ let drained = (self.pred)(&mut v[i]);
+ self.panic_flag = false;
+ // Update the index *after* the predicate is called. If the index
+ // is updated prior and the predicate panics, the element at this
+ // index would be leaked.
+ self.idx += 1;
+ if drained {
+ self.del += 1;
+ return Some(ptr::read(&v[i]));
+ } else if self.del > 0 {
+ let del = self.del;
+ let src: *const T = &v[i];
+ let dst: *mut T = &mut v[i - del];
+ ptr::copy_nonoverlapping(src, dst, 1);
+ }
+ }
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(self.old_len - self.idx))
+ }
+}
+
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
+where
+ F: FnMut(&mut T) -> bool,
+{
+ fn drop(&mut self) {
+ struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
+ where
+ F: FnMut(&mut T) -> bool,
+ {
+ drain: &'b mut DrainFilter<'a, T, F, A>,
+ }
+
+ impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
+ where
+ F: FnMut(&mut T) -> bool,
+ {
+ fn drop(&mut self) {
+ unsafe {
+ if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
+ // This is a pretty messed up state, and there isn't really an
+ // obviously right thing to do. We don't want to keep trying
+ // to execute `pred`, so we just backshift all the unprocessed
+ // elements and tell the vec that they still exist. The backshift
+ // is required to prevent a double-drop of the last successfully
+ // drained item prior to a panic in the predicate.
+ let ptr = self.drain.vec.as_mut_ptr();
+ let src = ptr.add(self.drain.idx);
+ let dst = src.sub(self.drain.del);
+ let tail_len = self.drain.old_len - self.drain.idx;
+ src.copy_to(dst, tail_len);
+ }
+ self.drain.vec.set_len(self.drain.old_len - self.drain.del);
+ }
+ }
+ }
+
+ let backshift = BackshiftOnDrop { drain: self };
+
+ // Attempt to consume any remaining elements if the filter predicate
+ // has not yet panicked. We'll backshift any remaining elements
+ // whether we've already panicked or if the consumption here panics.
+ if !backshift.drain.panic_flag {
+ backshift.drain.for_each(drop);
+ }
+ }
+}
--- /dev/null
+use core::ptr::{self};
+use core::slice::{self};
+
+// A helper struct for in-place iteration that drops the destination slice of iteration,
+// i.e. the head. The source slice (the tail) is dropped by IntoIter.
+pub(super) struct InPlaceDrop<T> {
+ pub(super) inner: *mut T,
+ pub(super) dst: *mut T,
+}
+
+impl<T> InPlaceDrop<T> {
+ fn len(&self) -> usize {
+ unsafe { self.dst.offset_from(self.inner) as usize }
+ }
+}
+
+impl<T> Drop for InPlaceDrop<T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len()));
+ }
+ }
+}
--- /dev/null
+use crate::alloc::{Allocator, Global};
+use crate::raw_vec::RawVec;
+use core::fmt;
+use core::intrinsics::arith_offset;
+use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess};
+use core::marker::PhantomData;
+use core::mem::{self};
+use core::ptr::{self, NonNull};
+use core::slice::{self};
+
+/// An iterator that moves out of a vector.
+///
+/// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec)
+/// (provided by the [`IntoIterator`] trait).
+///
+/// # Example
+///
+/// ```
+/// let v = vec![0, 1, 2];
+/// let iter: std::vec::IntoIter<_> = v.into_iter();
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IntoIter<
+ T,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
+ pub(super) buf: NonNull<T>,
+ pub(super) phantom: PhantomData<T>,
+ pub(super) cap: usize,
+ pub(super) alloc: A,
+ pub(super) ptr: *const T,
+ pub(super) end: *const T,
+}
+
+#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
+ }
+}
+
+impl<T, A: Allocator> IntoIter<T, A> {
+ /// Returns the remaining items of this iterator as a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let vec = vec!['a', 'b', 'c'];
+ /// let mut into_iter = vec.into_iter();
+ /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ /// let _ = into_iter.next().unwrap();
+ /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
+ /// ```
+ #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
+ pub fn as_slice(&self) -> &[T] {
+ unsafe { slice::from_raw_parts(self.ptr, self.len()) }
+ }
+
+ /// Returns the remaining items of this iterator as a mutable slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let vec = vec!['a', 'b', 'c'];
+ /// let mut into_iter = vec.into_iter();
+ /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ /// into_iter.as_mut_slice()[2] = 'z';
+ /// assert_eq!(into_iter.next().unwrap(), 'a');
+ /// assert_eq!(into_iter.next().unwrap(), 'b');
+ /// assert_eq!(into_iter.next().unwrap(), 'z');
+ /// ```
+ #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
+ pub fn as_mut_slice(&mut self) -> &mut [T] {
+ unsafe { &mut *self.as_raw_mut_slice() }
+ }
+
+ /// Returns a reference to the underlying allocator.
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ #[inline]
+ pub fn allocator(&self) -> &A {
+ &self.alloc
+ }
+
+ fn as_raw_mut_slice(&mut self) -> *mut [T] {
+ ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
+ }
+
+ pub(super) fn drop_remaining(&mut self) {
+ unsafe {
+ ptr::drop_in_place(self.as_mut_slice());
+ }
+ self.ptr = self.end;
+ }
+
+ /// Relinquishes the backing allocation, equivalent to
+ /// `ptr::write(&mut self, Vec::new().into_iter())`
+ pub(super) fn forget_allocation(&mut self) {
+ self.cap = 0;
+ self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) };
+ self.ptr = self.buf.as_ptr();
+ self.end = self.buf.as_ptr();
+ }
+}
+
+#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
+impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> {
+ fn as_ref(&self) -> &[T] {
+ self.as_slice()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync, A: Allocator> Sync for IntoIter<T, A> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> Iterator for IntoIter<T, A> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ if self.ptr as *const _ == self.end {
+ None
+ } else if mem::size_of::<T>() == 0 {
+ // purposefully don't use 'ptr.offset' because for
+ // vectors with 0-size elements this would return the
+ // same pointer.
+ self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
+
+ // Make up a value of this ZST.
+ Some(unsafe { mem::zeroed() })
+ } else {
+ let old = self.ptr;
+ self.ptr = unsafe { self.ptr.offset(1) };
+
+ Some(unsafe { ptr::read(old) })
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let exact = if mem::size_of::<T>() == 0 {
+ (self.end as usize).wrapping_sub(self.ptr as usize)
+ } else {
+ unsafe { self.end.offset_from(self.ptr) as usize }
+ };
+ (exact, Some(exact))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
+ where
+ Self: TrustedRandomAccess,
+ {
+ // SAFETY: the caller must guarantee that `i` is in bounds of the
+ // `Vec<T>`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)`
+ // is guaranteed to pointer to an element of the `Vec<T>` and
+ // thus guaranteed to be valid to dereference.
+ //
+ // Also note the implementation of `Self: TrustedRandomAccess` requires
+ // that `T: Copy` so reading elements from the buffer doesn't invalidate
+ // them for `Drop`.
+ unsafe {
+ if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> {
+ if self.end == self.ptr {
+ None
+ } else if mem::size_of::<T>() == 0 {
+ // See above for why 'ptr.offset' isn't used
+ self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T };
+
+ // Make up a value of this ZST.
+ Some(unsafe { mem::zeroed() })
+ } else {
+ self.end = unsafe { self.end.offset(-1) };
+
+ Some(unsafe { ptr::read(self.end) })
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
+ fn is_empty(&self) -> bool {
+ self.ptr == self.end
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
+
+#[doc(hidden)]
+#[unstable(issue = "none", feature = "std_internals")]
+// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
+// and thus we can't implement drop-handling
+unsafe impl<T, A: Allocator> TrustedRandomAccess for IntoIter<T, A>
+where
+ T: Copy,
+{
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
+impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
+ #[cfg(not(test))]
+ fn clone(&self) -> Self {
+ self.as_slice().to_vec_in(self.alloc.clone()).into_iter()
+ }
+ #[cfg(test)]
+ fn clone(&self) -> Self {
+ crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
+ fn drop(&mut self) {
+ struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>);
+
+ impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
+ fn drop(&mut self) {
+ unsafe {
+ // `IntoIter::alloc` is not used anymore after this
+ let alloc = ptr::read(&self.0.alloc);
+ // RawVec handles deallocation
+ let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc);
+ }
+ }
+ }
+
+ let guard = DropGuard(self);
+ // destroy the remaining elements
+ unsafe {
+ ptr::drop_in_place(guard.0.as_raw_mut_slice());
+ }
+ // now `guard` will be dropped and do the rest
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
+ type Source = Self;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut Self::Source {
+ self
+ }
+}
+
+// internal helper trait for in-place iteration specialization.
+#[rustc_specialization_trait]
+pub(crate) trait AsIntoIter {
+ type Item;
+ fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item>;
+}
+
+impl<T> AsIntoIter for IntoIter<T> {
+ type Item = T;
+
+ fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
+ self
+ }
+}
--- /dev/null
+use crate::boxed::Box;
+
+#[rustc_specialization_trait]
+pub(super) unsafe trait IsZero {
+ /// Whether this value is zero
+ fn is_zero(&self) -> bool;
+}
+
+macro_rules! impl_is_zero {
+ ($t:ty, $is_zero:expr) => {
+ unsafe impl IsZero for $t {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ $is_zero(*self)
+ }
+ }
+ };
+}
+
+impl_is_zero!(i16, |x| x == 0);
+impl_is_zero!(i32, |x| x == 0);
+impl_is_zero!(i64, |x| x == 0);
+impl_is_zero!(i128, |x| x == 0);
+impl_is_zero!(isize, |x| x == 0);
+
+impl_is_zero!(u16, |x| x == 0);
+impl_is_zero!(u32, |x| x == 0);
+impl_is_zero!(u64, |x| x == 0);
+impl_is_zero!(u128, |x| x == 0);
+impl_is_zero!(usize, |x| x == 0);
+
+impl_is_zero!(bool, |x| x == false);
+impl_is_zero!(char, |x| x == '\0');
+
+impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
+impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
+
+unsafe impl<T> IsZero for *const T {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ (*self).is_null()
+ }
+}
+
+unsafe impl<T> IsZero for *mut T {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ (*self).is_null()
+ }
+}
+
+// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
+// For fat pointers, the bytes that would be the pointer metadata in the `Some`
+// variant are padding in the `None` variant, so ignoring them and
+// zero-initializing instead is ok.
+// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
+// `SpecFromElem`.
+
+unsafe impl<T: ?Sized> IsZero for Option<&T> {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ self.is_none()
+ }
+}
+
+unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ self.is_none()
+ }
+}
--- /dev/null
+//! A contiguous growable array type with heap-allocated contents, written
+//! `Vec<T>`.
+//!
+//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and
+//! `O(1)` pop (from the end).
+//!
+//! Vectors ensure they never allocate more than `isize::MAX` bytes.
+//!
+//! # Examples
+//!
+//! You can explicitly create a [`Vec`] with [`Vec::new`]:
+//!
+//! ```
+//! let v: Vec<i32> = Vec::new();
+//! ```
+//!
+//! ...or by using the [`vec!`] macro:
+//!
+//! ```
+//! let v: Vec<i32> = vec![];
+//!
+//! let v = vec![1, 2, 3, 4, 5];
+//!
+//! let v = vec![0; 10]; // ten zeroes
+//! ```
+//!
+//! You can [`push`] values onto the end of a vector (which will grow the vector
+//! as needed):
+//!
+//! ```
+//! let mut v = vec![1, 2];
+//!
+//! v.push(3);
+//! ```
+//!
+//! Popping values works in much the same way:
+//!
+//! ```
+//! let mut v = vec![1, 2];
+//!
+//! let two = v.pop();
+//! ```
+//!
+//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits):
+//!
+//! ```
+//! let mut v = vec![1, 2, 3];
+//! let three = v[2];
+//! v[1] = v[1] + 5;
+//! ```
+//!
+//! [`push`]: Vec::push
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use core::cmp::{self, Ordering};
+use core::convert::TryFrom;
+use core::fmt;
+use core::hash::{Hash, Hasher};
+use core::intrinsics::{arith_offset, assume};
+use core::iter::FromIterator;
+use core::marker::PhantomData;
+use core::mem::{self, ManuallyDrop, MaybeUninit};
+use core::ops::{self, Index, IndexMut, Range, RangeBounds};
+use core::ptr::{self, NonNull};
+use core::slice::{self, SliceIndex};
+
+use crate::alloc::{Allocator, Global};
+use crate::borrow::{Cow, ToOwned};
+use crate::boxed::Box;
+use crate::collections::TryReserveError;
+use crate::raw_vec::RawVec;
+
+#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+pub use self::drain_filter::DrainFilter;
+
+mod drain_filter;
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+pub use self::splice::Splice;
+
+mod splice;
+
+#[stable(feature = "drain", since = "1.6.0")]
+pub use self::drain::Drain;
+
+mod drain;
+
+mod cow;
+
+pub(crate) use self::into_iter::AsIntoIter;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::into_iter::IntoIter;
+
+mod into_iter;
+
+use self::is_zero::IsZero;
+
+mod is_zero;
+
+mod source_iter_marker;
+
+mod partial_eq;
+
+use self::spec_from_elem::SpecFromElem;
+
+mod spec_from_elem;
+
+use self::set_len_on_drop::SetLenOnDrop;
+
+mod set_len_on_drop;
+
+use self::in_place_drop::InPlaceDrop;
+
+mod in_place_drop;
+
+use self::spec_from_iter_nested::SpecFromIterNested;
+
+mod spec_from_iter_nested;
+
+use self::spec_from_iter::SpecFromIter;
+
+mod spec_from_iter;
+
+use self::spec_extend::SpecExtend;
+
+mod spec_extend;
+
+/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
+///
+/// # Examples
+///
+/// ```
+/// let mut vec = Vec::new();
+/// vec.push(1);
+/// vec.push(2);
+///
+/// assert_eq!(vec.len(), 2);
+/// assert_eq!(vec[0], 1);
+///
+/// assert_eq!(vec.pop(), Some(2));
+/// assert_eq!(vec.len(), 1);
+///
+/// vec[0] = 7;
+/// assert_eq!(vec[0], 7);
+///
+/// vec.extend([1, 2, 3].iter().copied());
+///
+/// for x in &vec {
+/// println!("{}", x);
+/// }
+/// assert_eq!(vec, [7, 1, 2, 3]);
+/// ```
+///
+/// The [`vec!`] macro is provided to make initialization more convenient:
+///
+/// ```
+/// let mut vec = vec![1, 2, 3];
+/// vec.push(4);
+/// assert_eq!(vec, [1, 2, 3, 4]);
+/// ```
+///
+/// It can also initialize each element of a `Vec<T>` with a given value.
+/// This may be more efficient than performing allocation and initialization
+/// in separate steps, especially when initializing a vector of zeros:
+///
+/// ```
+/// let vec = vec![0; 5];
+/// assert_eq!(vec, [0, 0, 0, 0, 0]);
+///
+/// // The following is equivalent, but potentially slower:
+/// let mut vec = Vec::with_capacity(5);
+/// vec.resize(5, 0);
+/// assert_eq!(vec, [0, 0, 0, 0, 0]);
+/// ```
+///
+/// For more information, see
+/// [Capacity and Reallocation](#capacity-and-reallocation).
+///
+/// Use a `Vec<T>` as an efficient stack:
+///
+/// ```
+/// let mut stack = Vec::new();
+///
+/// stack.push(1);
+/// stack.push(2);
+/// stack.push(3);
+///
+/// while let Some(top) = stack.pop() {
+/// // Prints 3, 2, 1
+/// println!("{}", top);
+/// }
+/// ```
+///
+/// # Indexing
+///
+/// The `Vec` type allows to access values by index, because it implements the
+/// [`Index`] trait. An example will be more explicit:
+///
+/// ```
+/// let v = vec![0, 2, 4, 6];
+/// println!("{}", v[1]); // it will display '2'
+/// ```
+///
+/// However be careful: if you try to access an index which isn't in the `Vec`,
+/// your software will panic! You cannot do this:
+///
+/// ```should_panic
+/// let v = vec![0, 2, 4, 6];
+/// println!("{}", v[6]); // it will panic!
+/// ```
+///
+/// Use [`get`] and [`get_mut`] if you want to check whether the index is in
+/// the `Vec`.
+///
+/// # Slicing
+///
+/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects.
+/// To get a [slice], use [`&`]. Example:
+///
+/// ```
+/// fn read_slice(slice: &[usize]) {
+/// // ...
+/// }
+///
+/// let v = vec![0, 1];
+/// read_slice(&v);
+///
+/// // ... and that's all!
+/// // you can also do it like this:
+/// let u: &[usize] = &v;
+/// // or like this:
+/// let u: &[_] = &v;
+/// ```
+///
+/// In Rust, it's more common to pass slices as arguments rather than vectors
+/// when you just want to provide read access. The same goes for [`String`] and
+/// [`&str`].
+///
+/// # Capacity and reallocation
+///
+/// The capacity of a vector is the amount of space allocated for any future
+/// elements that will be added onto the vector. This is not to be confused with
+/// the *length* of a vector, which specifies the number of actual elements
+/// within the vector. If a vector's length exceeds its capacity, its capacity
+/// will automatically be increased, but its elements will have to be
+/// reallocated.
+///
+/// For example, a vector with capacity 10 and length 0 would be an empty vector
+/// with space for 10 more elements. Pushing 10 or fewer elements onto the
+/// vector will not change its capacity or cause reallocation to occur. However,
+/// if the vector's length is increased to 11, it will have to reallocate, which
+/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`]
+/// whenever possible to specify how big the vector is expected to get.
+///
+/// # Guarantees
+///
+/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees
+/// about its design. This ensures that it's as low-overhead as possible in
+/// the general case, and can be correctly manipulated in primitive ways
+/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<T>`.
+/// If additional type parameters are added (e.g., to support custom allocators),
+/// overriding their defaults may change the behavior.
+///
+/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length)
+/// triplet. No more, no less. The order of these fields is completely
+/// unspecified, and you should use the appropriate methods to modify these.
+/// The pointer will never be null, so this type is null-pointer-optimized.
+///
+/// However, the pointer may not actually point to allocated memory. In particular,
+/// if you construct a `Vec` with capacity 0 via [`Vec::new`], [`vec![]`][`vec!`],
+/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit`]
+/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
+/// types inside a `Vec`, it will not allocate space for them. *Note that in this case
+/// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only
+/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation
+/// details are very subtle — if you intend to allocate memory using a `Vec`
+/// and use it for something else (either to pass to unsafe code, or to build your
+/// own memory-backed collection), be sure to deallocate this memory by using
+/// `from_raw_parts` to recover the `Vec` and then dropping it.
+///
+/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
+/// (as defined by the allocator Rust is configured to use by default), and its
+/// pointer points to [`len`] initialized, contiguous elements in order (what
+/// you would see if you coerced it to a slice), followed by [`capacity`]` -
+/// `[`len`] logically uninitialized, contiguous elements.
+///
+/// `Vec` will never perform a "small optimization" where elements are actually
+/// stored on the stack for two reasons:
+///
+/// * It would make it more difficult for unsafe code to correctly manipulate
+/// a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were
+/// only moved, and it would be more difficult to determine if a `Vec` had
+/// actually allocated memory.
+///
+/// * It would penalize the general case, incurring an additional branch
+/// on every access.
+///
+/// `Vec` will never automatically shrink itself, even if completely empty. This
+/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec`
+/// and then filling it back up to the same [`len`] should incur no calls to
+/// the allocator. If you wish to free up unused memory, use
+/// [`shrink_to_fit`].
+///
+/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
+/// sufficient. [`push`] and [`insert`] *will* (re)allocate if
+/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely
+/// accurate, and can be relied on. It can even be used to manually free the memory
+/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
+/// when not necessary.
+///
+/// `Vec` does not guarantee any particular growth strategy when reallocating
+/// when full, nor when [`reserve`] is called. The current strategy is basic
+/// and it may prove desirable to use a non-constant growth factor. Whatever
+/// strategy is used will of course guarantee *O*(1) amortized [`push`].
+///
+/// `vec![x; n]`, `vec![a, b, c, d]`, and
+/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
+/// with exactly the requested capacity. If [`len`]` == `[`capacity`],
+/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
+/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
+///
+/// `Vec` will not specifically overwrite any data that is removed from it,
+/// but also won't specifically preserve it. Its uninitialized memory is
+/// scratch space that it may use however it wants. It will generally just do
+/// whatever is most efficient or otherwise easy to implement. Do not rely on
+/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
+/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
+/// first, that may not actually happen because the optimizer does not consider
+/// this a side-effect that must be preserved. There is one case which we will
+/// not break, however: using `unsafe` code to write to the excess capacity,
+/// and then increasing the length to match, is always valid.
+///
+/// `Vec` does not currently guarantee the order in which elements are dropped.
+/// The order has changed in the past and may change again.
+///
+/// [`get`]: ../../std/vec/struct.Vec.html#method.get
+/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut
+/// [`String`]: crate::string::String
+/// [`&str`]: type@str
+/// [`shrink_to_fit`]: Vec::shrink_to_fit
+/// [`capacity`]: Vec::capacity
+/// [`mem::size_of::<T>`]: core::mem::size_of
+/// [`len`]: Vec::len
+/// [`push`]: Vec::push
+/// [`insert`]: Vec::insert
+/// [`reserve`]: Vec::reserve
+/// [owned slice]: Box
+/// [slice]: ../../std/primitive.slice.html
+/// [`&`]: ../../std/primitive.reference.html
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
+pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
+ buf: RawVec<T, A>,
+ len: usize,
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Inherent methods
+////////////////////////////////////////////////////////////////////////////////
+
+impl<T> Vec<T> {
+ /// Constructs a new, empty `Vec<T>`.
+ ///
+ /// The vector will not allocate until elements are pushed onto it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # #![allow(unused_mut)]
+ /// let mut vec: Vec<i32> = Vec::new();
+ /// ```
+ #[inline]
+ #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const fn new() -> Self {
+ Vec { buf: RawVec::NEW, len: 0 }
+ }
+
+ /// Constructs a new, empty `Vec<T>` with the specified capacity.
+ ///
+ /// The vector will be able to hold exactly `capacity` elements without
+ /// reallocating. If `capacity` is 0, the vector will not allocate.
+ ///
+ /// It is important to note that although the returned vector has the
+ /// *capacity* specified, the vector will have a zero *length*. For an
+ /// explanation of the difference between length and capacity, see
+ /// *[Capacity and reallocation]*.
+ ///
+ /// [Capacity and reallocation]: #capacity-and-reallocation
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = Vec::with_capacity(10);
+ ///
+ /// // The vector contains no items, even though it has capacity for more
+ /// assert_eq!(vec.len(), 0);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // These are all done without reallocating...
+ /// for i in 0..10 {
+ /// vec.push(i);
+ /// }
+ /// assert_eq!(vec.len(), 10);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // ...but this may make the vector reallocate
+ /// vec.push(11);
+ /// assert_eq!(vec.len(), 11);
+ /// assert!(vec.capacity() >= 11);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_capacity(capacity: usize) -> Self {
+ Self::with_capacity_in(capacity, Global)
+ }
+
+ /// Creates a `Vec<T>` directly from the raw components of another vector.
+ ///
+ /// # Safety
+ ///
+ /// This is highly unsafe, due to the number of invariants that aren't
+ /// checked:
+ ///
+ /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
+ /// (at least, it's highly likely to be incorrect if it wasn't).
+ /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
+ /// (`T` having a less strict alignment is not sufficient, the alignment really
+ /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
+ /// allocated and deallocated with the same layout.)
+ /// * `length` needs to be less than or equal to `capacity`.
+ /// * `capacity` needs to be the capacity that the pointer was allocated with.
+ ///
+ /// Violating these may cause problems like corrupting the allocator's
+ /// internal data structures. For example it is **not** safe
+ /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
+ /// It's also not safe to build one from a `Vec<u16>` and its length, because
+ /// the allocator cares about the alignment, and these two types have different
+ /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
+ /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
+ ///
+ /// The ownership of `ptr` is effectively transferred to the
+ /// `Vec<T>` which may then deallocate, reallocate or change the
+ /// contents of memory pointed to by the pointer at will. Ensure
+ /// that nothing else uses the pointer after calling this
+ /// function.
+ ///
+ /// [`String`]: crate::string::String
+ /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ptr;
+ /// use std::mem;
+ ///
+ /// let v = vec![1, 2, 3];
+ ///
+ // FIXME Update this when vec_into_raw_parts is stabilized
+ /// // Prevent running `v`'s destructor so we are in complete control
+ /// // of the allocation.
+ /// let mut v = mem::ManuallyDrop::new(v);
+ ///
+ /// // Pull out the various important pieces of information about `v`
+ /// let p = v.as_mut_ptr();
+ /// let len = v.len();
+ /// let cap = v.capacity();
+ ///
+ /// unsafe {
+ /// // Overwrite memory with 4, 5, 6
+ /// for i in 0..len as isize {
+ /// ptr::write(p.offset(i), 4 + i);
+ /// }
+ ///
+ /// // Put everything back together into a Vec
+ /// let rebuilt = Vec::from_raw_parts(p, len, cap);
+ /// assert_eq!(rebuilt, [4, 5, 6]);
+ /// }
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
+ unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }
+ }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+ /// Constructs a new, empty `Vec<T, A>`.
+ ///
+ /// The vector will not allocate until elements are pushed onto it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(allocator_api)]
+ ///
+ /// use std::alloc::System;
+ ///
+ /// # #[allow(unused_mut)]
+ /// let mut vec: Vec<i32, _> = Vec::new_in(System);
+ /// ```
+ #[inline]
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ pub const fn new_in(alloc: A) -> Self {
+ Vec { buf: RawVec::new_in(alloc), len: 0 }
+ }
+
+ /// Constructs a new, empty `Vec<T, A>` with the specified capacity with the provided
+ /// allocator.
+ ///
+ /// The vector will be able to hold exactly `capacity` elements without
+ /// reallocating. If `capacity` is 0, the vector will not allocate.
+ ///
+ /// It is important to note that although the returned vector has the
+ /// *capacity* specified, the vector will have a zero *length*. For an
+ /// explanation of the difference between length and capacity, see
+ /// *[Capacity and reallocation]*.
+ ///
+ /// [Capacity and reallocation]: #capacity-and-reallocation
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(allocator_api)]
+ ///
+ /// use std::alloc::System;
+ ///
+ /// let mut vec = Vec::with_capacity_in(10, System);
+ ///
+ /// // The vector contains no items, even though it has capacity for more
+ /// assert_eq!(vec.len(), 0);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // These are all done without reallocating...
+ /// for i in 0..10 {
+ /// vec.push(i);
+ /// }
+ /// assert_eq!(vec.len(), 10);
+ /// assert_eq!(vec.capacity(), 10);
+ ///
+ /// // ...but this may make the vector reallocate
+ /// vec.push(11);
+ /// assert_eq!(vec.len(), 11);
+ /// assert!(vec.capacity() >= 11);
+ /// ```
+ #[inline]
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
+ Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
+ }
+
+ /// Creates a `Vec<T, A>` directly from the raw components of another vector.
+ ///
+ /// # Safety
+ ///
+ /// This is highly unsafe, due to the number of invariants that aren't
+ /// checked:
+ ///
+ /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
+ /// (at least, it's highly likely to be incorrect if it wasn't).
+ /// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
+ /// (`T` having a less strict alignment is not sufficient, the alignment really
+ /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
+ /// allocated and deallocated with the same layout.)
+ /// * `length` needs to be less than or equal to `capacity`.
+ /// * `capacity` needs to be the capacity that the pointer was allocated with.
+ ///
+ /// Violating these may cause problems like corrupting the allocator's
+ /// internal data structures. For example it is **not** safe
+ /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
+ /// It's also not safe to build one from a `Vec<u16>` and its length, because
+ /// the allocator cares about the alignment, and these two types have different
+ /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
+ /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
+ ///
+ /// The ownership of `ptr` is effectively transferred to the
+ /// `Vec<T>` which may then deallocate, reallocate or change the
+ /// contents of memory pointed to by the pointer at will. Ensure
+ /// that nothing else uses the pointer after calling this
+ /// function.
+ ///
+ /// [`String`]: crate::string::String
+ /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(allocator_api)]
+ ///
+ /// use std::alloc::System;
+ ///
+ /// use std::ptr;
+ /// use std::mem;
+ ///
+ /// let mut v = Vec::with_capacity_in(3, System);
+ /// v.push(1);
+ /// v.push(2);
+ /// v.push(3);
+ ///
+ // FIXME Update this when vec_into_raw_parts is stabilized
+ /// // Prevent running `v`'s destructor so we are in complete control
+ /// // of the allocation.
+ /// let mut v = mem::ManuallyDrop::new(v);
+ ///
+ /// // Pull out the various important pieces of information about `v`
+ /// let p = v.as_mut_ptr();
+ /// let len = v.len();
+ /// let cap = v.capacity();
+ /// let alloc = v.allocator();
+ ///
+ /// unsafe {
+ /// // Overwrite memory with 4, 5, 6
+ /// for i in 0..len as isize {
+ /// ptr::write(p.offset(i), 4 + i);
+ /// }
+ ///
+ /// // Put everything back together into a Vec
+ /// let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone());
+ /// assert_eq!(rebuilt, [4, 5, 6]);
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
+ unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
+ }
+
+ /// Decomposes a `Vec<T>` into its raw components.
+ ///
+ /// Returns the raw pointer to the underlying data, the length of
+ /// the vector (in elements), and the allocated capacity of the
+ /// data (in elements). These are the same arguments in the same
+ /// order as the arguments to [`from_raw_parts`].
+ ///
+ /// After calling this function, the caller is responsible for the
+ /// memory previously managed by the `Vec`. The only way to do
+ /// this is to convert the raw pointer, length, and capacity back
+ /// into a `Vec` with the [`from_raw_parts`] function, allowing
+ /// the destructor to perform the cleanup.
+ ///
+ /// [`from_raw_parts`]: Vec::from_raw_parts
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(vec_into_raw_parts)]
+ /// let v: Vec<i32> = vec![-1, 0, 1];
+ ///
+ /// let (ptr, len, cap) = v.into_raw_parts();
+ ///
+ /// let rebuilt = unsafe {
+ /// // We can now make changes to the components, such as
+ /// // transmuting the raw pointer to a compatible type.
+ /// let ptr = ptr as *mut u32;
+ ///
+ /// Vec::from_raw_parts(ptr, len, cap)
+ /// };
+ /// assert_eq!(rebuilt, [4294967295, 0, 1]);
+ /// ```
+ #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
+ pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
+ let mut me = ManuallyDrop::new(self);
+ (me.as_mut_ptr(), me.len(), me.capacity())
+ }
+
+ /// Decomposes a `Vec<T>` into its raw components.
+ ///
+ /// Returns the raw pointer to the underlying data, the length of the vector (in elements),
+ /// the allocated capacity of the data (in elements), and the allocator. These are the same
+ /// arguments in the same order as the arguments to [`from_raw_parts_in`].
+ ///
+ /// After calling this function, the caller is responsible for the
+ /// memory previously managed by the `Vec`. The only way to do
+ /// this is to convert the raw pointer, length, and capacity back
+ /// into a `Vec` with the [`from_raw_parts_in`] function, allowing
+ /// the destructor to perform the cleanup.
+ ///
+ /// [`from_raw_parts_in`]: Vec::from_raw_parts_in
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(allocator_api, vec_into_raw_parts)]
+ ///
+ /// use std::alloc::System;
+ ///
+ /// let mut v: Vec<i32, System> = Vec::new_in(System);
+ /// v.push(-1);
+ /// v.push(0);
+ /// v.push(1);
+ ///
+ /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
+ ///
+ /// let rebuilt = unsafe {
+ /// // We can now make changes to the components, such as
+ /// // transmuting the raw pointer to a compatible type.
+ /// let ptr = ptr as *mut u32;
+ ///
+ /// Vec::from_raw_parts_in(ptr, len, cap, alloc)
+ /// };
+ /// assert_eq!(rebuilt, [4294967295, 0, 1]);
+ /// ```
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
+ pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) {
+ let mut me = ManuallyDrop::new(self);
+ let len = me.len();
+ let capacity = me.capacity();
+ let ptr = me.as_mut_ptr();
+ let alloc = unsafe { ptr::read(me.allocator()) };
+ (ptr, len, capacity, alloc)
+ }
+
+ /// Returns the number of elements the vector can hold without
+ /// reallocating.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let vec: Vec<i32> = Vec::with_capacity(10);
+ /// assert_eq!(vec.capacity(), 10);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn capacity(&self) -> usize {
+ self.buf.capacity()
+ }
+
+ /// Reserves capacity for at least `additional` more elements to be inserted
+ /// in the given `Vec<T>`. The collection may reserve more space to avoid
+ /// frequent reallocations. After calling `reserve`, capacity will be
+ /// greater than or equal to `self.len() + additional`. Does nothing if
+ /// capacity is already sufficient.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1];
+ /// vec.reserve(10);
+ /// assert!(vec.capacity() >= 11);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn reserve(&mut self, additional: usize) {
+ self.buf.reserve(self.len, additional);
+ }
+
+ /// Reserves the minimum capacity for exactly `additional` more elements to
+ /// be inserted in the given `Vec<T>`. After calling `reserve_exact`,
+ /// capacity will be greater than or equal to `self.len() + additional`.
+ /// Does nothing if the capacity is already sufficient.
+ ///
+ /// Note that the allocator may give the collection more space than it
+ /// requests. Therefore, capacity can not be relied upon to be precisely
+ /// minimal. Prefer `reserve` if future insertions are expected.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new capacity overflows `usize`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1];
+ /// vec.reserve_exact(10);
+ /// assert!(vec.capacity() >= 11);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.buf.reserve_exact(self.len, additional);
+ }
+
+ /// Tries to reserve capacity for at least `additional` more elements to be inserted
+ /// in the given `Vec<T>`. The collection may reserve more space to avoid
+ /// frequent reallocations. After calling `try_reserve`, capacity will be
+ /// greater than or equal to `self.len() + additional`. Does nothing if
+ /// capacity is already sufficient.
+ ///
+ /// # Errors
+ ///
+ /// If the capacity overflows, or the allocator reports a failure, then an error
+ /// is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(try_reserve)]
+ /// use std::collections::TryReserveError;
+ ///
+ /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
+ /// let mut output = Vec::new();
+ ///
+ /// // Pre-reserve the memory, exiting if we can't
+ /// output.try_reserve(data.len())?;
+ ///
+ /// // Now we know this can't OOM in the middle of our complex work
+ /// output.extend(data.iter().map(|&val| {
+ /// val * 2 + 5 // very complicated
+ /// }));
+ ///
+ /// Ok(output)
+ /// }
+ /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+ /// ```
+ #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
+ pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.buf.try_reserve(self.len, additional)
+ }
+
+ /// Tries to reserve the minimum capacity for exactly `additional`
+ /// elements to be inserted in the given `Vec<T>`. After calling
+ /// `try_reserve_exact`, capacity will be greater than or equal to
+ /// `self.len() + additional` if it returns `Ok(())`.
+ /// Does nothing if the capacity is already sufficient.
+ ///
+ /// Note that the allocator may give the collection more space than it
+ /// requests. Therefore, capacity can not be relied upon to be precisely
+ /// minimal. Prefer `reserve` if future insertions are expected.
+ ///
+ /// # Errors
+ ///
+ /// If the capacity overflows, or the allocator reports a failure, then an error
+ /// is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(try_reserve)]
+ /// use std::collections::TryReserveError;
+ ///
+ /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
+ /// let mut output = Vec::new();
+ ///
+ /// // Pre-reserve the memory, exiting if we can't
+ /// output.try_reserve_exact(data.len())?;
+ ///
+ /// // Now we know this can't OOM in the middle of our complex work
+ /// output.extend(data.iter().map(|&val| {
+ /// val * 2 + 5 // very complicated
+ /// }));
+ ///
+ /// Ok(output)
+ /// }
+ /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+ /// ```
+ #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
+ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.buf.try_reserve_exact(self.len, additional)
+ }
+
+ /// Shrinks the capacity of the vector as much as possible.
+ ///
+ /// It will drop down as close as possible to the length but the allocator
+ /// may still inform the vector that there is space for a few more elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = Vec::with_capacity(10);
+ /// vec.extend([1, 2, 3].iter().cloned());
+ /// assert_eq!(vec.capacity(), 10);
+ /// vec.shrink_to_fit();
+ /// assert!(vec.capacity() >= 3);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn shrink_to_fit(&mut self) {
+ // The capacity is never less than the length, and there's nothing to do when
+ // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit`
+ // by only calling it with a greater capacity.
+ if self.capacity() > self.len {
+ self.buf.shrink_to_fit(self.len);
+ }
+ }
+
+ /// Shrinks the capacity of the vector with a lower bound.
+ ///
+ /// The capacity will remain at least as large as both the length
+ /// and the supplied value.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the current capacity is smaller than the supplied
+ /// minimum capacity.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(shrink_to)]
+ /// let mut vec = Vec::with_capacity(10);
+ /// vec.extend([1, 2, 3].iter().cloned());
+ /// assert_eq!(vec.capacity(), 10);
+ /// vec.shrink_to(4);
+ /// assert!(vec.capacity() >= 4);
+ /// vec.shrink_to(0);
+ /// assert!(vec.capacity() >= 3);
+ /// ```
+ #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.buf.shrink_to_fit(cmp::max(self.len, min_capacity));
+ }
+
+ /// Converts the vector into [`Box<[T]>`][owned slice].
+ ///
+ /// Note that this will drop any excess capacity.
+ ///
+ /// [owned slice]: Box
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = vec![1, 2, 3];
+ ///
+ /// let slice = v.into_boxed_slice();
+ /// ```
+ ///
+ /// Any excess capacity is removed:
+ ///
+ /// ```
+ /// let mut vec = Vec::with_capacity(10);
+ /// vec.extend([1, 2, 3].iter().cloned());
+ ///
+ /// assert_eq!(vec.capacity(), 10);
+ /// let slice = vec.into_boxed_slice();
+ /// assert_eq!(slice.into_vec().capacity(), 3);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_boxed_slice(mut self) -> Box<[T], A> {
+ unsafe {
+ self.shrink_to_fit();
+ let me = ManuallyDrop::new(self);
+ let buf = ptr::read(&me.buf);
+ let len = me.len();
+ buf.into_box(len).assume_init()
+ }
+ }
+
+ /// Shortens the vector, keeping the first `len` elements and dropping
+ /// the rest.
+ ///
+ /// If `len` is greater than the vector's current length, this has no
+ /// effect.
+ ///
+ /// The [`drain`] method can emulate `truncate`, but causes the excess
+ /// elements to be returned instead of dropped.
+ ///
+ /// Note that this method has no effect on the allocated capacity
+ /// of the vector.
+ ///
+ /// # Examples
+ ///
+ /// Truncating a five element vector to two elements:
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3, 4, 5];
+ /// vec.truncate(2);
+ /// assert_eq!(vec, [1, 2]);
+ /// ```
+ ///
+ /// No truncation occurs when `len` is greater than the vector's current
+ /// length:
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3];
+ /// vec.truncate(8);
+ /// assert_eq!(vec, [1, 2, 3]);
+ /// ```
+ ///
+ /// Truncating when `len == 0` is equivalent to calling the [`clear`]
+ /// method.
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3];
+ /// vec.truncate(0);
+ /// assert_eq!(vec, []);
+ /// ```
+ ///
+ /// [`clear`]: Vec::clear
+ /// [`drain`]: Vec::drain
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn truncate(&mut self, len: usize) {
+ // This is safe because:
+ //
+ // * the slice passed to `drop_in_place` is valid; the `len > self.len`
+ // case avoids creating an invalid slice, and
+ // * the `len` of the vector is shrunk before calling `drop_in_place`,
+ // such that no value will be dropped twice in case `drop_in_place`
+ // were to panic once (if it panics twice, the program aborts).
+ unsafe {
+ if len > self.len {
+ return;
+ }
+ let remaining_len = self.len - len;
+ let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len);
+ self.len = len;
+ ptr::drop_in_place(s);
+ }
+ }
+
+ /// Extracts a slice containing the entire vector.
+ ///
+ /// Equivalent to `&s[..]`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{self, Write};
+ /// let buffer = vec![1, 2, 3, 5, 8];
+ /// io::sink().write(buffer.as_slice()).unwrap();
+ /// ```
+ #[inline]
+ #[stable(feature = "vec_as_slice", since = "1.7.0")]
+ pub fn as_slice(&self) -> &[T] {
+ self
+ }
+
+ /// Extracts a mutable slice of the entire vector.
+ ///
+ /// Equivalent to `&mut s[..]`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{self, Read};
+ /// let mut buffer = vec![0; 3];
+ /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap();
+ /// ```
+ #[inline]
+ #[stable(feature = "vec_as_slice", since = "1.7.0")]
+ pub fn as_mut_slice(&mut self) -> &mut [T] {
+ self
+ }
+
+ /// Returns a raw pointer to the vector's buffer.
+ ///
+ /// The caller must ensure that the vector outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ /// Modifying the vector may cause its buffer to be reallocated,
+ /// which would also make any pointers to it invalid.
+ ///
+ /// The caller must also ensure that the memory the pointer (non-transitively) points to
+ /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
+ /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = vec![1, 2, 4];
+ /// let x_ptr = x.as_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// assert_eq!(*x_ptr.add(i), 1 << i);
+ /// }
+ /// }
+ /// ```
+ ///
+ /// [`as_mut_ptr`]: Vec::as_mut_ptr
+ #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+ #[inline]
+ pub fn as_ptr(&self) -> *const T {
+ // We shadow the slice method of the same name to avoid going through
+ // `deref`, which creates an intermediate reference.
+ let ptr = self.buf.ptr();
+ unsafe {
+ assume(!ptr.is_null());
+ }
+ ptr
+ }
+
+ /// Returns an unsafe mutable pointer to the vector's buffer.
+ ///
+ /// The caller must ensure that the vector outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ /// Modifying the vector may cause its buffer to be reallocated,
+ /// which would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// // Allocate vector big enough for 4 elements.
+ /// let size = 4;
+ /// let mut x: Vec<i32> = Vec::with_capacity(size);
+ /// let x_ptr = x.as_mut_ptr();
+ ///
+ /// // Initialize elements via raw pointer writes, then set length.
+ /// unsafe {
+ /// for i in 0..size {
+ /// *x_ptr.add(i) = i as i32;
+ /// }
+ /// x.set_len(size);
+ /// }
+ /// assert_eq!(&*x, &[0, 1, 2, 3]);
+ /// ```
+ #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ // We shadow the slice method of the same name to avoid going through
+ // `deref_mut`, which creates an intermediate reference.
+ let ptr = self.buf.ptr();
+ unsafe {
+ assume(!ptr.is_null());
+ }
+ ptr
+ }
+
+ /// Returns a reference to the underlying allocator.
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ #[inline]
+ pub fn allocator(&self) -> &A {
+ self.buf.allocator()
+ }
+
+ /// Forces the length of the vector to `new_len`.
+ ///
+ /// This is a low-level operation that maintains none of the normal
+ /// invariants of the type. Normally changing the length of a vector
+ /// is done using one of the safe operations instead, such as
+ /// [`truncate`], [`resize`], [`extend`], or [`clear`].
+ ///
+ /// [`truncate`]: Vec::truncate
+ /// [`resize`]: Vec::resize
+ /// [`extend`]: Extend::extend
+ /// [`clear`]: Vec::clear
+ ///
+ /// # Safety
+ ///
+ /// - `new_len` must be less than or equal to [`capacity()`].
+ /// - The elements at `old_len..new_len` must be initialized.
+ ///
+ /// [`capacity()`]: Vec::capacity
+ ///
+ /// # Examples
+ ///
+ /// This method can be useful for situations in which the vector
+ /// is serving as a buffer for other code, particularly over FFI:
+ ///
+ /// ```no_run
+ /// # #![allow(dead_code)]
+ /// # // This is just a minimal skeleton for the doc example;
+ /// # // don't use this as a starting point for a real library.
+ /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void }
+ /// # const Z_OK: i32 = 0;
+ /// # extern "C" {
+ /// # fn deflateGetDictionary(
+ /// # strm: *mut std::ffi::c_void,
+ /// # dictionary: *mut u8,
+ /// # dictLength: *mut usize,
+ /// # ) -> i32;
+ /// # }
+ /// # impl StreamWrapper {
+ /// pub fn get_dictionary(&self) -> Option<Vec<u8>> {
+ /// // Per the FFI method's docs, "32768 bytes is always enough".
+ /// let mut dict = Vec::with_capacity(32_768);
+ /// let mut dict_length = 0;
+ /// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that:
+ /// // 1. `dict_length` elements were initialized.
+ /// // 2. `dict_length` <= the capacity (32_768)
+ /// // which makes `set_len` safe to call.
+ /// unsafe {
+ /// // Make the FFI call...
+ /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length);
+ /// if r == Z_OK {
+ /// // ...and update the length to what was initialized.
+ /// dict.set_len(dict_length);
+ /// Some(dict)
+ /// } else {
+ /// None
+ /// }
+ /// }
+ /// }
+ /// # }
+ /// ```
+ ///
+ /// While the following example is sound, there is a memory leak since
+ /// the inner vectors were not freed prior to the `set_len` call:
+ ///
+ /// ```
+ /// let mut vec = vec![vec![1, 0, 0],
+ /// vec![0, 1, 0],
+ /// vec![0, 0, 1]];
+ /// // SAFETY:
+ /// // 1. `old_len..0` is empty so no elements need to be initialized.
+ /// // 2. `0 <= capacity` always holds whatever `capacity` is.
+ /// unsafe {
+ /// vec.set_len(0);
+ /// }
+ /// ```
+ ///
+ /// Normally, here, one would use [`clear`] instead to correctly drop
+ /// the contents and thus not leak memory.
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub unsafe fn set_len(&mut self, new_len: usize) {
+ debug_assert!(new_len <= self.capacity());
+
+ self.len = new_len;
+ }
+
+ /// Removes an element from the vector and returns it.
+ ///
+ /// The removed element is replaced by the last element of the vector.
+ ///
+ /// This does not preserve ordering, but is O(1).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = vec!["foo", "bar", "baz", "qux"];
+ ///
+ /// assert_eq!(v.swap_remove(1), "bar");
+ /// assert_eq!(v, ["foo", "qux", "baz"]);
+ ///
+ /// assert_eq!(v.swap_remove(0), "foo");
+ /// assert_eq!(v, ["baz", "qux"]);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn swap_remove(&mut self, index: usize) -> T {
+ #[cold]
+ #[inline(never)]
+ fn assert_failed(index: usize, len: usize) -> ! {
+ panic!("swap_remove index (is {}) should be < len (is {})", index, len);
+ }
+
+ let len = self.len();
+ if index >= len {
+ assert_failed(index, len);
+ }
+ unsafe {
+ // We replace self[index] with the last element. Note that if the
+ // bounds check above succeeds there must be a last element (which
+ // can be self[index] itself).
+ let last = ptr::read(self.as_ptr().add(len - 1));
+ let hole = self.as_mut_ptr().add(index);
+ self.set_len(len - 1);
+ ptr::replace(hole, last)
+ }
+ }
+
+ /// Inserts an element at position `index` within the vector, shifting all
+ /// elements after it to the right.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3];
+ /// vec.insert(1, 4);
+ /// assert_eq!(vec, [1, 4, 2, 3]);
+ /// vec.insert(4, 5);
+ /// assert_eq!(vec, [1, 4, 2, 3, 5]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn insert(&mut self, index: usize, element: T) {
+ #[cold]
+ #[inline(never)]
+ fn assert_failed(index: usize, len: usize) -> ! {
+ panic!("insertion index (is {}) should be <= len (is {})", index, len);
+ }
+
+ let len = self.len();
+ if index > len {
+ assert_failed(index, len);
+ }
+
+ // space for the new element
+ if len == self.buf.capacity() {
+ self.reserve(1);
+ }
+
+ unsafe {
+ // infallible
+ // The spot to put the new value
+ {
+ let p = self.as_mut_ptr().add(index);
+ // Shift everything over to make space. (Duplicating the
+ // `index`th element into two consecutive places.)
+ ptr::copy(p, p.offset(1), len - index);
+ // Write it in, overwriting the first copy of the `index`th
+ // element.
+ ptr::write(p, element);
+ }
+ self.set_len(len + 1);
+ }
+ }
+
+ /// Removes and returns the element at position `index` within the vector,
+ /// shifting all elements after it to the left.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = vec![1, 2, 3];
+ /// assert_eq!(v.remove(1), 2);
+ /// assert_eq!(v, [1, 3]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn remove(&mut self, index: usize) -> T {
+ #[cold]
+ #[inline(never)]
+ fn assert_failed(index: usize, len: usize) -> ! {
+ panic!("removal index (is {}) should be < len (is {})", index, len);
+ }
+
+ let len = self.len();
+ if index >= len {
+ assert_failed(index, len);
+ }
+ unsafe {
+ // infallible
+ let ret;
+ {
+ // the place we are taking from.
+ let ptr = self.as_mut_ptr().add(index);
+ // copy it out, unsafely having a copy of the value on
+ // the stack and in the vector at the same time.
+ ret = ptr::read(ptr);
+
+ // Shift everything down to fill in that spot.
+ ptr::copy(ptr.offset(1), ptr, len - index - 1);
+ }
+ self.set_len(len - 1);
+ ret
+ }
+ }
+
+ /// Retains only the elements specified by the predicate.
+ ///
+ /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ /// This method operates in place, visiting each element exactly once in the
+ /// original order, and preserves the order of the retained elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3, 4];
+ /// vec.retain(|&x| x % 2 == 0);
+ /// assert_eq!(vec, [2, 4]);
+ /// ```
+ ///
+ /// The exact order may be useful for tracking external state, like an index.
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3, 4, 5];
+ /// let keep = [false, true, true, false, true];
+ /// let mut i = 0;
+ /// vec.retain(|_| (keep[i], i += 1).0);
+ /// assert_eq!(vec, [2, 3, 5]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn retain<F>(&mut self, mut f: F)
+ where
+ F: FnMut(&T) -> bool,
+ {
+ let len = self.len();
+ let mut del = 0;
+ {
+ let v = &mut **self;
+
+ for i in 0..len {
+ if !f(&v[i]) {
+ del += 1;
+ } else if del > 0 {
+ v.swap(i - del, i);
+ }
+ }
+ }
+ if del > 0 {
+ self.truncate(len - del);
+ }
+ }
+
+ /// Removes all but the first of consecutive elements in the vector that resolve to the same
+ /// key.
+ ///
+ /// If the vector is sorted, this removes all duplicates.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![10, 20, 21, 30, 20];
+ ///
+ /// vec.dedup_by_key(|i| *i / 10);
+ ///
+ /// assert_eq!(vec, [10, 20, 30, 20]);
+ /// ```
+ #[stable(feature = "dedup_by", since = "1.16.0")]
+ #[inline]
+ pub fn dedup_by_key<F, K>(&mut self, mut key: F)
+ where
+ F: FnMut(&mut T) -> K,
+ K: PartialEq,
+ {
+ self.dedup_by(|a, b| key(a) == key(b))
+ }
+
+ /// Removes all but the first of consecutive elements in the vector satisfying a given equality
+ /// relation.
+ ///
+ /// The `same_bucket` function is passed references to two elements from the vector and
+ /// must determine if the elements compare equal. The elements are passed in opposite order
+ /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
+ ///
+ /// If the vector is sorted, this removes all duplicates.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
+ ///
+ /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+ ///
+ /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+ /// ```
+ #[stable(feature = "dedup_by", since = "1.16.0")]
+ pub fn dedup_by<F>(&mut self, same_bucket: F)
+ where
+ F: FnMut(&mut T, &mut T) -> bool,
+ {
+ let len = {
+ let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
+ dedup.len()
+ };
+ self.truncate(len);
+ }
+
+ /// Appends an element to the back of a collection.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2];
+ /// vec.push(3);
+ /// assert_eq!(vec, [1, 2, 3]);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn push(&mut self, value: T) {
+ // This will panic or abort if we would allocate > isize::MAX bytes
+ // or if the length increment would overflow for zero-sized types.
+ if self.len == self.buf.capacity() {
+ self.reserve(1);
+ }
+ unsafe {
+ let end = self.as_mut_ptr().add(self.len);
+ ptr::write(end, value);
+ self.len += 1;
+ }
+ }
+
+ /// Removes the last element from a vector and returns it, or [`None`] if it
+ /// is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3];
+ /// assert_eq!(vec.pop(), Some(3));
+ /// assert_eq!(vec, [1, 2]);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn pop(&mut self) -> Option<T> {
+ if self.len == 0 {
+ None
+ } else {
+ unsafe {
+ self.len -= 1;
+ Some(ptr::read(self.as_ptr().add(self.len())))
+ }
+ }
+ }
+
+ /// Moves all the elements of `other` into `Self`, leaving `other` empty.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the number of elements in the vector overflows a `usize`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3];
+ /// let mut vec2 = vec![4, 5, 6];
+ /// vec.append(&mut vec2);
+ /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(vec2, []);
+ /// ```
+ #[inline]
+ #[stable(feature = "append", since = "1.4.0")]
+ pub fn append(&mut self, other: &mut Self) {
+ unsafe {
+ self.append_elements(other.as_slice() as _);
+ other.set_len(0);
+ }
+ }
+
+ /// Appends elements to `Self` from other buffer.
+ #[inline]
+ unsafe fn append_elements(&mut self, other: *const [T]) {
+ let count = unsafe { (*other).len() };
+ self.reserve(count);
+ let len = self.len();
+ unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
+ self.len += count;
+ }
+
+ /// Creates a draining iterator that removes the specified range in the vector
+ /// and yields the removed items.
+ ///
+ /// When the iterator **is** dropped, all elements in the range are removed
+ /// from the vector, even if the iterator was not fully consumed. If the
+ /// iterator **is not** dropped (with [`mem::forget`] for example), it is
+ /// unspecified how many elements are removed.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the starting point is greater than the end point or if
+ /// the end point is greater than the length of the vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = vec![1, 2, 3];
+ /// let u: Vec<_> = v.drain(1..).collect();
+ /// assert_eq!(v, &[1]);
+ /// assert_eq!(u, &[2, 3]);
+ ///
+ /// // A full range clears the vector
+ /// v.drain(..);
+ /// assert_eq!(v, &[]);
+ /// ```
+ #[stable(feature = "drain", since = "1.6.0")]
+ pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
+ where
+ R: RangeBounds<usize>,
+ {
+ // Memory safety
+ //
+ // When the Drain is first created, it shortens the length of
+ // the source vector to make sure no uninitialized or moved-from elements
+ // are accessible at all if the Drain's destructor never gets to run.
+ //
+ // Drain will ptr::read out the values to remove.
+ // When finished, remaining tail of the vec is copied back to cover
+ // the hole, and the vector length is restored to the new length.
+ //
+ let len = self.len();
+ let Range { start, end } = range.assert_len(len);
+
+ unsafe {
+ // set self.vec length's to start, to be safe in case Drain is leaked
+ self.set_len(start);
+ // Use the borrow in the IterMut to indicate borrowing behavior of the
+ // whole Drain iterator (like &mut T).
+ let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start);
+ Drain {
+ tail_start: end,
+ tail_len: len - end,
+ iter: range_slice.iter(),
+ vec: NonNull::from(self),
+ }
+ }
+ }
+
+ /// Clears the vector, removing all values.
+ ///
+ /// Note that this method has no effect on the allocated capacity
+ /// of the vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = vec![1, 2, 3];
+ ///
+ /// v.clear();
+ ///
+ /// assert!(v.is_empty());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn clear(&mut self) {
+ self.truncate(0)
+ }
+
+ /// Returns the number of elements in the vector, also referred to
+ /// as its 'length'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let a = vec![1, 2, 3];
+ /// assert_eq!(a.len(), 3);
+ /// ```
+ #[doc(alias = "length")]
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ /// Returns `true` if the vector contains no elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = Vec::new();
+ /// assert!(v.is_empty());
+ ///
+ /// v.push(1);
+ /// assert!(!v.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Splits the collection into two at the given index.
+ ///
+ /// Returns a newly allocated vector containing the elements in the range
+ /// `[at, len)`. After the call, the original vector will be left containing
+ /// the elements `[0, at)` with its previous capacity unchanged.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `at > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3];
+ /// let vec2 = vec.split_off(1);
+ /// assert_eq!(vec, [1]);
+ /// assert_eq!(vec2, [2, 3]);
+ /// ```
+ #[inline]
+ #[must_use = "use `.truncate()` if you don't need the other half"]
+ #[stable(feature = "split_off", since = "1.4.0")]
+ pub fn split_off(&mut self, at: usize) -> Self
+ where
+ A: Clone,
+ {
+ #[cold]
+ #[inline(never)]
+ fn assert_failed(at: usize, len: usize) -> ! {
+ panic!("`at` split index (is {}) should be <= len (is {})", at, len);
+ }
+
+ if at > self.len() {
+ assert_failed(at, self.len());
+ }
+
+ if at == 0 {
+ // the new vector can take over the original buffer and avoid the copy
+ return mem::replace(
+ self,
+ Vec::with_capacity_in(self.capacity(), self.allocator().clone()),
+ );
+ }
+
+ let other_len = self.len - at;
+ let mut other = Vec::with_capacity_in(other_len, self.allocator().clone());
+
+ // Unsafely `set_len` and copy items to `other`.
+ unsafe {
+ self.set_len(at);
+ other.set_len(other_len);
+
+ ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other.len());
+ }
+ other
+ }
+
+ /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
+ ///
+ /// If `new_len` is greater than `len`, the `Vec` is extended by the
+ /// difference, with each additional slot filled with the result of
+ /// calling the closure `f`. The return values from `f` will end up
+ /// in the `Vec` in the order they have been generated.
+ ///
+ /// If `new_len` is less than `len`, the `Vec` is simply truncated.
+ ///
+ /// This method uses a closure to create new values on every push. If
+ /// you'd rather [`Clone`] a given value, use [`Vec::resize`]. If you
+ /// want to use the [`Default`] trait to generate values, you can
+ /// pass [`Default::default`] as the second argument.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 3];
+ /// vec.resize_with(5, Default::default);
+ /// assert_eq!(vec, [1, 2, 3, 0, 0]);
+ ///
+ /// let mut vec = vec![];
+ /// let mut p = 1;
+ /// vec.resize_with(4, || { p *= 2; p });
+ /// assert_eq!(vec, [2, 4, 8, 16]);
+ /// ```
+ #[stable(feature = "vec_resize_with", since = "1.33.0")]
+ pub fn resize_with<F>(&mut self, new_len: usize, f: F)
+ where
+ F: FnMut() -> T,
+ {
+ let len = self.len();
+ if new_len > len {
+ self.extend_with(new_len - len, ExtendFunc(f));
+ } else {
+ self.truncate(new_len);
+ }
+ }
+
+ /// Consumes and leaks the `Vec`, returning a mutable reference to the contents,
+ /// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime
+ /// `'a`. If the type has only static references, or none at all, then this
+ /// may be chosen to be `'static`.
+ ///
+ /// This function is similar to the [`leak`][Box::leak] function on [`Box`]
+ /// except that there is no way to recover the leaked memory.
+ ///
+ /// This function is mainly useful for data that lives for the remainder of
+ /// the program's life. Dropping the returned reference will cause a memory
+ /// leak.
+ ///
+ /// # Examples
+ ///
+ /// Simple usage:
+ ///
+ /// ```
+ /// let x = vec![1, 2, 3];
+ /// let static_ref: &'static mut [usize] = x.leak();
+ /// static_ref[0] += 1;
+ /// assert_eq!(static_ref, &[2, 2, 3]);
+ /// ```
+ #[stable(feature = "vec_leak", since = "1.47.0")]
+ #[inline]
+ pub fn leak<'a>(self) -> &'a mut [T]
+ where
+ A: 'a,
+ {
+ Box::leak(self.into_boxed_slice())
+ }
+
+ /// Returns the remaining spare capacity of the vector as a slice of
+ /// `MaybeUninit<T>`.
+ ///
+ /// The returned slice can be used to fill the vector with data (e.g. by
+ /// reading from a file) before marking the data as initialized using the
+ /// [`set_len`] method.
+ ///
+ /// [`set_len`]: Vec::set_len
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(vec_spare_capacity, maybe_uninit_extra)]
+ ///
+ /// // Allocate vector big enough for 10 elements.
+ /// let mut v = Vec::with_capacity(10);
+ ///
+ /// // Fill in the first 3 elements.
+ /// let uninit = v.spare_capacity_mut();
+ /// uninit[0].write(0);
+ /// uninit[1].write(1);
+ /// uninit[2].write(2);
+ ///
+ /// // Mark the first 3 elements of the vector as being initialized.
+ /// unsafe {
+ /// v.set_len(3);
+ /// }
+ ///
+ /// assert_eq!(&v, &[0, 1, 2]);
+ /// ```
+ #[unstable(feature = "vec_spare_capacity", issue = "75017")]
+ #[inline]
+ pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
+ self.buf.capacity() - self.len,
+ )
+ }
+ }
+}
+
+impl<T: Clone, A: Allocator> Vec<T, A> {
+ /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
+ ///
+ /// If `new_len` is greater than `len`, the `Vec` is extended by the
+ /// difference, with each additional slot filled with `value`.
+ /// If `new_len` is less than `len`, the `Vec` is simply truncated.
+ ///
+ /// This method requires `T` to implement [`Clone`],
+ /// in order to be able to clone the passed value.
+ /// If you need more flexibility (or want to rely on [`Default`] instead of
+ /// [`Clone`]), use [`Vec::resize_with`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec!["hello"];
+ /// vec.resize(3, "world");
+ /// assert_eq!(vec, ["hello", "world", "world"]);
+ ///
+ /// let mut vec = vec![1, 2, 3, 4];
+ /// vec.resize(2, 0);
+ /// assert_eq!(vec, [1, 2]);
+ /// ```
+ #[stable(feature = "vec_resize", since = "1.5.0")]
+ pub fn resize(&mut self, new_len: usize, value: T) {
+ let len = self.len();
+
+ if new_len > len {
+ self.extend_with(new_len - len, ExtendElement(value))
+ } else {
+ self.truncate(new_len);
+ }
+ }
+
+ /// Clones and appends all elements in a slice to the `Vec`.
+ ///
+ /// Iterates over the slice `other`, clones each element, and then appends
+ /// it to this `Vec`. The `other` vector is traversed in-order.
+ ///
+ /// Note that this function is same as [`extend`] except that it is
+ /// specialized to work with slices instead. If and when Rust gets
+ /// specialization this function will likely be deprecated (but still
+ /// available).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1];
+ /// vec.extend_from_slice(&[2, 3, 4]);
+ /// assert_eq!(vec, [1, 2, 3, 4]);
+ /// ```
+ ///
+ /// [`extend`]: Vec::extend
+ #[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
+ pub fn extend_from_slice(&mut self, other: &[T]) {
+ self.spec_extend(other.iter())
+ }
+}
+
+// This code generalizes `extend_with_{element,default}`.
+trait ExtendWith<T> {
+ fn next(&mut self) -> T;
+ fn last(self) -> T;
+}
+
+struct ExtendElement<T>(T);
+impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
+ fn next(&mut self) -> T {
+ self.0.clone()
+ }
+ fn last(self) -> T {
+ self.0
+ }
+}
+
+struct ExtendDefault;
+impl<T: Default> ExtendWith<T> for ExtendDefault {
+ fn next(&mut self) -> T {
+ Default::default()
+ }
+ fn last(self) -> T {
+ Default::default()
+ }
+}
+
+struct ExtendFunc<F>(F);
+impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
+ fn next(&mut self) -> T {
+ (self.0)()
+ }
+ fn last(mut self) -> T {
+ (self.0)()
+ }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+ /// Extend the vector by `n` values, using the given generator.
+ fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
+ self.reserve(n);
+
+ unsafe {
+ let mut ptr = self.as_mut_ptr().add(self.len());
+ // Use SetLenOnDrop to work around bug where compiler
+ // may not realize the store through `ptr` through self.set_len()
+ // don't alias.
+ let mut local_len = SetLenOnDrop::new(&mut self.len);
+
+ // Write all elements except the last one
+ for _ in 1..n {
+ ptr::write(ptr, value.next());
+ ptr = ptr.offset(1);
+ // Increment the length in every step in case next() panics
+ local_len.increment_len(1);
+ }
+
+ if n > 0 {
+ // We can write the last element directly without cloning needlessly
+ ptr::write(ptr, value.last());
+ local_len.increment_len(1);
+ }
+
+ // len set by scope guard
+ }
+ }
+}
+
+impl<T: PartialEq, A: Allocator> Vec<T, A> {
+ /// Removes consecutive repeated elements in the vector according to the
+ /// [`PartialEq`] trait implementation.
+ ///
+ /// If the vector is sorted, this removes all duplicates.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec![1, 2, 2, 3, 2];
+ ///
+ /// vec.dedup();
+ ///
+ /// assert_eq!(vec, [1, 2, 3, 2]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn dedup(&mut self) {
+ self.dedup_by(|a, b| a == b)
+ }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+ /// Removes the first instance of `item` from the vector if the item exists.
+ ///
+ /// This method will be removed soon.
+ #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
+ #[rustc_deprecated(
+ reason = "Removing the first item equal to a needle is already easily possible \
+ with iterators and the current Vec methods. Furthermore, having a method for \
+ one particular case of removal (linear search, only the first item, no swap remove) \
+ but not for others is inconsistent. This method will be removed soon.",
+ since = "1.46.0"
+ )]
+ pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
+ where
+ T: PartialEq<V>,
+ {
+ let pos = self.iter().position(|x| *x == *item)?;
+ Some(self.remove(pos))
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Internal methods and functions
+////////////////////////////////////////////////////////////////////////////////
+
+#[doc(hidden)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
+ <T as SpecFromElem>::from_elem(elem, n, Global)
+}
+
+#[doc(hidden)]
+#[unstable(feature = "allocator_api", issue = "32838")]
+pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
+ <T as SpecFromElem>::from_elem(elem, n, alloc)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Common trait implementations for Vec
+////////////////////////////////////////////////////////////////////////////////
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> ops::Deref for Vec<T, A> {
+ type Target = [T];
+
+ fn deref(&self) -> &[T] {
+ unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
+ fn deref_mut(&mut self) -> &mut [T] {
+ unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
+ #[cfg(not(test))]
+ fn clone(&self) -> Self {
+ let alloc = self.allocator().clone();
+ <[T]>::to_vec_in(&**self, alloc)
+ }
+
+ // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
+ // required for this method definition, is not available. Instead use the
+ // `slice::to_vec` function which is only available with cfg(test)
+ // NB see the slice::hack module in slice.rs for more information
+ #[cfg(test)]
+ fn clone(&self) -> Self {
+ let alloc = self.allocator().clone();
+ crate::slice::to_vec(&**self, alloc)
+ }
+
+ fn clone_from(&mut self, other: &Self) {
+ // drop anything that will not be overwritten
+ self.truncate(other.len());
+
+ // self.len <= other.len due to the truncate above, so the
+ // slices here are always in-bounds.
+ let (init, tail) = other.split_at(self.len());
+
+ // reuse the contained values' allocations/resources.
+ self.clone_from_slice(init);
+ self.extend_from_slice(tail);
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ Hash::hash(&**self, state)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented(
+ message = "vector indices are of type `usize` or ranges of `usize`",
+ label = "vector indices are of type `usize` or ranges of `usize`"
+)]
+impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
+ type Output = I::Output;
+
+ #[inline]
+ fn index(&self, index: I) -> &Self::Output {
+ Index::index(&**self, index)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented(
+ message = "vector indices are of type `usize` or ranges of `usize`",
+ label = "vector indices are of type `usize` or ranges of `usize`"
+)]
+impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
+ #[inline]
+ fn index_mut(&mut self, index: I) -> &mut Self::Output {
+ IndexMut::index_mut(&mut **self, index)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> FromIterator<T> for Vec<T> {
+ #[inline]
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
+ <Self as SpecFromIter<T, I::IntoIter>>::from_iter(iter.into_iter())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> IntoIterator for Vec<T, A> {
+ type Item = T;
+ type IntoIter = IntoIter<T, A>;
+
+ /// Creates a consuming iterator, that is, one that moves each value out of
+ /// the vector (from start to end). The vector cannot be used after calling
+ /// this.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = vec!["a".to_string(), "b".to_string()];
+ /// for s in v.into_iter() {
+ /// // s has type String, not &String
+ /// println!("{}", s);
+ /// }
+ /// ```
+ #[inline]
+ fn into_iter(self) -> IntoIter<T, A> {
+ unsafe {
+ let mut me = ManuallyDrop::new(self);
+ let alloc = ptr::read(me.allocator());
+ let begin = me.as_mut_ptr();
+ let end = if mem::size_of::<T>() == 0 {
+ arith_offset(begin as *const i8, me.len() as isize) as *const T
+ } else {
+ begin.add(me.len()) as *const T
+ };
+ let cap = me.buf.capacity();
+ IntoIter {
+ buf: NonNull::new_unchecked(begin),
+ phantom: PhantomData,
+ cap,
+ alloc,
+ ptr: begin,
+ end,
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
+ type Item = &'a T;
+ type IntoIter = slice::Iter<'a, T>;
+
+ fn into_iter(self) -> slice::Iter<'a, T> {
+ self.iter()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
+ type Item = &'a mut T;
+ type IntoIter = slice::IterMut<'a, T>;
+
+ fn into_iter(self) -> slice::IterMut<'a, T> {
+ self.iter_mut()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> Extend<T> for Vec<T, A> {
+ #[inline]
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
+ }
+
+ #[inline]
+ fn extend_one(&mut self, item: T) {
+ self.push(item);
+ }
+
+ #[inline]
+ fn extend_reserve(&mut self, additional: usize) {
+ self.reserve(additional);
+ }
+}
+
+impl<T, A: Allocator> Vec<T, A> {
+ // leaf method to which various SpecFrom/SpecExtend implementations delegate when
+ // they have no further optimizations to apply
+ fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
+ // This is the case for a general iterator.
+ //
+ // This function should be the moral equivalent of:
+ //
+ // for item in iterator {
+ // self.push(item);
+ // }
+ while let Some(element) = iterator.next() {
+ let len = self.len();
+ if len == self.capacity() {
+ let (lower, _) = iterator.size_hint();
+ self.reserve(lower.saturating_add(1));
+ }
+ unsafe {
+ ptr::write(self.as_mut_ptr().add(len), element);
+ // NB can't overflow since we would have had to alloc the address space
+ self.set_len(len + 1);
+ }
+ }
+ }
+
+ /// Creates a splicing iterator that replaces the specified range in the vector
+ /// with the given `replace_with` iterator and yields the removed items.
+ /// `replace_with` does not need to be the same length as `range`.
+ ///
+ /// `range` is removed even if the iterator is not consumed until the end.
+ ///
+ /// It is unspecified how many elements are removed from the vector
+ /// if the `Splice` value is leaked.
+ ///
+ /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped.
+ ///
+ /// This is optimal if:
+ ///
+ /// * The tail (elements in the vector after `range`) is empty,
+ /// * or `replace_with` yields fewer elements than `range`’s length
+ /// * or the lower bound of its `size_hint()` is exact.
+ ///
+ /// Otherwise, a temporary vector is allocated and the tail is moved twice.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the starting point is greater than the end point or if
+ /// the end point is greater than the length of the vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = vec![1, 2, 3];
+ /// let new = [7, 8];
+ /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
+ /// assert_eq!(v, &[7, 8, 3]);
+ /// assert_eq!(u, &[1, 2]);
+ /// ```
+ #[inline]
+ #[stable(feature = "vec_splice", since = "1.21.0")]
+ pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
+ where
+ R: RangeBounds<usize>,
+ I: IntoIterator<Item = T>,
+ {
+ Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
+ }
+
+ /// Creates an iterator which uses a closure to determine if an element should be removed.
+ ///
+ /// If the closure returns true, then the element is removed and yielded.
+ /// If the closure returns false, the element will remain in the vector and will not be yielded
+ /// by the iterator.
+ ///
+ /// Using this method is equivalent to the following code:
+ ///
+ /// ```
+ /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
+ /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
+ /// let mut i = 0;
+ /// while i != vec.len() {
+ /// if some_predicate(&mut vec[i]) {
+ /// let val = vec.remove(i);
+ /// // your code here
+ /// } else {
+ /// i += 1;
+ /// }
+ /// }
+ ///
+ /// # assert_eq!(vec, vec![1, 4, 5]);
+ /// ```
+ ///
+ /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
+ /// because it can backshift the elements of the array in bulk.
+ ///
+ /// Note that `drain_filter` also lets you mutate every element in the filter closure,
+ /// regardless of whether you choose to keep or remove it.
+ ///
+ /// # Examples
+ ///
+ /// Splitting an array into evens and odds, reusing the original allocation:
+ ///
+ /// ```
+ /// #![feature(drain_filter)]
+ /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
+ ///
+ /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+ /// let odds = numbers;
+ ///
+ /// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
+ /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
+ /// ```
+ #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
+ pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
+ where
+ F: FnMut(&mut T) -> bool,
+ {
+ let old_len = self.len();
+
+ // Guard against us getting leaked (leak amplification)
+ unsafe {
+ self.set_len(0);
+ }
+
+ DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
+ }
+}
+
+/// Extend implementation that copies elements out of references before pushing them onto the Vec.
+///
+/// This implementation is specialized for slice iterators, where it uses [`copy_from_slice`] to
+/// append the entire slice at once.
+///
+/// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
+ fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+ self.spec_extend(iter.into_iter())
+ }
+
+ #[inline]
+ fn extend_one(&mut self, &item: &'a T) {
+ self.push(item);
+ }
+
+ #[inline]
+ fn extend_reserve(&mut self, additional: usize) {
+ self.reserve(additional);
+ }
+}
+
+/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ PartialOrd::partial_cmp(&**self, &**other)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Eq, A: Allocator> Eq for Vec<T, A> {}
+
+/// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord, A: Allocator> Ord for Vec<T, A> {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ Ord::cmp(&**self, &**other)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
+ fn drop(&mut self) {
+ unsafe {
+ // use drop for [T]
+ // use a raw slice to refer to the elements of the vector as weakest necessary type;
+ // could avoid questions of validity in certain cases
+ ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len))
+ }
+ // RawVec handles deallocation
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Default for Vec<T> {
+ /// Creates an empty `Vec<T>`.
+ fn default() -> Vec<T> {
+ Vec::new()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> AsRef<Vec<T, A>> for Vec<T, A> {
+ fn as_ref(&self) -> &Vec<T, A> {
+ self
+ }
+}
+
+#[stable(feature = "vec_as_mut", since = "1.5.0")]
+impl<T, A: Allocator> AsMut<Vec<T, A>> for Vec<T, A> {
+ fn as_mut(&mut self) -> &mut Vec<T, A> {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, A: Allocator> AsRef<[T]> for Vec<T, A> {
+ fn as_ref(&self) -> &[T] {
+ self
+ }
+}
+
+#[stable(feature = "vec_as_mut", since = "1.5.0")]
+impl<T, A: Allocator> AsMut<[T]> for Vec<T, A> {
+ fn as_mut(&mut self) -> &mut [T] {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone> From<&[T]> for Vec<T> {
+ #[cfg(not(test))]
+ fn from(s: &[T]) -> Vec<T> {
+ s.to_vec()
+ }
+ #[cfg(test)]
+ fn from(s: &[T]) -> Vec<T> {
+ crate::slice::to_vec(s, Global)
+ }
+}
+
+#[stable(feature = "vec_from_mut", since = "1.19.0")]
+impl<T: Clone> From<&mut [T]> for Vec<T> {
+ #[cfg(not(test))]
+ fn from(s: &mut [T]) -> Vec<T> {
+ s.to_vec()
+ }
+ #[cfg(test)]
+ fn from(s: &mut [T]) -> Vec<T> {
+ crate::slice::to_vec(s, Global)
+ }
+}
+
+#[stable(feature = "vec_from_array", since = "1.44.0")]
+impl<T, const N: usize> From<[T; N]> for Vec<T> {
+ #[cfg(not(test))]
+ fn from(s: [T; N]) -> Vec<T> {
+ <[T]>::into_vec(box s)
+ }
+ #[cfg(test)]
+ fn from(s: [T; N]) -> Vec<T> {
+ crate::slice::into_vec(box s)
+ }
+}
+
+#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
+impl<'a, T> From<Cow<'a, [T]>> for Vec<T>
+where
+ [T]: ToOwned<Owned = Vec<T>>,
+{
+ fn from(s: Cow<'a, [T]>) -> Vec<T> {
+ s.into_owned()
+ }
+}
+
+// note: test pulls in libstd, which causes errors here
+#[cfg(not(test))]
+#[stable(feature = "vec_from_box", since = "1.18.0")]
+impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
+ fn from(s: Box<[T], A>) -> Self {
+ let len = s.len();
+ Self { buf: RawVec::from_box(s), len }
+ }
+}
+
+// note: test pulls in libstd, which causes errors here
+#[cfg(not(test))]
+#[stable(feature = "box_from_vec", since = "1.20.0")]
+impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
+ fn from(v: Vec<T, A>) -> Self {
+ v.into_boxed_slice()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<&str> for Vec<u8> {
+ fn from(s: &str) -> Vec<u8> {
+ From::from(s.as_bytes())
+ }
+}
+
+#[stable(feature = "array_try_from_vec", since = "1.48.0")]
+impl<T, A: Allocator, const N: usize> TryFrom<Vec<T, A>> for [T; N] {
+ type Error = Vec<T, A>;
+
+ /// Gets the entire contents of the `Vec<T>` as an array,
+ /// if its size exactly matches that of the requested array.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
+ /// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
+ /// ```
+ ///
+ /// If the length doesn't match, the input comes back in `Err`:
+ /// ```
+ /// use std::convert::TryInto;
+ /// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
+ /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
+ /// ```
+ ///
+ /// If you're fine with just getting a prefix of the `Vec<T>`,
+ /// you can call [`.truncate(N)`](Vec::truncate) first.
+ /// ```
+ /// use std::convert::TryInto;
+ /// let mut v = String::from("hello world").into_bytes();
+ /// v.sort();
+ /// v.truncate(2);
+ /// let [a, b]: [_; 2] = v.try_into().unwrap();
+ /// assert_eq!(a, b' ');
+ /// assert_eq!(b, b'd');
+ /// ```
+ fn try_from(mut vec: Vec<T, A>) -> Result<[T; N], Vec<T, A>> {
+ if vec.len() != N {
+ return Err(vec);
+ }
+
+ // SAFETY: `.set_len(0)` is always sound.
+ unsafe { vec.set_len(0) };
+
+ // SAFETY: A `Vec`'s pointer is always aligned properly, and
+ // the alignment the array needs is the same as the items.
+ // We checked earlier that we have sufficient items.
+ // The items will not double-drop as the `set_len`
+ // tells the `Vec` not to also drop them.
+ let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) };
+ Ok(array)
+ }
+}
--- /dev/null
+use crate::alloc::Allocator;
+use crate::borrow::Cow;
+
+use super::Vec;
+
+macro_rules! __impl_slice_eq1 {
+ ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => {
+ #[$stability]
+ impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
+ where
+ T: PartialEq<U>,
+ $($ty: $bound)?
+ {
+ #[inline]
+ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
+ #[inline]
+ fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
+ }
+ }
+}
+
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, Vec<U, A>, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
+__impl_slice_eq1! { [A: Allocator] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
+__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] }
+
+// NOTE: some less important impls are omitted to reduce code bloat
+// FIXME(Centril): Reconsider this?
+//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], }
+//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], }
--- /dev/null
+// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
+//
+// The idea is: The length field in SetLenOnDrop is a local variable
+// that the optimizer will see does not alias with any stores through the Vec's data
+// pointer. This is a workaround for alias analysis issue #32155
+pub(super) struct SetLenOnDrop<'a> {
+ len: &'a mut usize,
+ local_len: usize,
+}
+
+impl<'a> SetLenOnDrop<'a> {
+ #[inline]
+ pub(super) fn new(len: &'a mut usize) -> Self {
+ SetLenOnDrop { local_len: *len, len }
+ }
+
+ #[inline]
+ pub(super) fn increment_len(&mut self, increment: usize) {
+ self.local_len += increment;
+ }
+}
+
+impl Drop for SetLenOnDrop<'_> {
+ #[inline]
+ fn drop(&mut self) {
+ *self.len = self.local_len;
+ }
+}
--- /dev/null
+use core::iter::{InPlaceIterable, SourceIter};
+use core::mem::{self, ManuallyDrop};
+use core::ptr::{self};
+
+use super::{AsIntoIter, InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec};
+
+/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
+/// source allocation, i.e. executing the pipeline in place.
+///
+/// The SourceIter parent trait is necessary for the specializing function to access the allocation
+/// which is to be reused. But it is not sufficient for the specialization to be valid. See
+/// additional bounds on the impl.
+#[rustc_unsafe_specialization_marker]
+pub(super) trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
+
+// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
+// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
+// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
+// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
+// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
+// several other specializations already depend on.
+impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
+
+impl<T, I> SpecFromIter<T, I> for Vec<T>
+where
+ I: Iterator<Item = T> + SourceIterMarker,
+{
+ default fn from_iter(mut iterator: I) -> Self {
+ // Additional requirements which cannot expressed via trait bounds. We rely on const eval
+ // instead:
+ // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
+ // b) size match as required by Alloc contract
+ // c) alignments match as required by Alloc contract
+ if mem::size_of::<T>() == 0
+ || mem::size_of::<T>()
+ != mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
+ || mem::align_of::<T>()
+ != mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
+ {
+ // fallback to more generic implementations
+ return SpecFromIterNested::from_iter(iterator);
+ }
+
+ let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
+ let inner = iterator.as_inner().as_into_iter();
+ (
+ inner.buf.as_ptr(),
+ inner.ptr,
+ inner.buf.as_ptr() as *mut T,
+ inner.end as *const T,
+ inner.cap,
+ )
+ };
+
+ // use try-fold since
+ // - it vectorizes better for some iterator adapters
+ // - unlike most internal iteration methods, it only takes a &mut self
+ // - it lets us thread the write pointer through its innards and get it back in the end
+ let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
+ let sink = iterator
+ .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
+ .unwrap();
+ // iteration succeeded, don't drop head
+ let dst = ManuallyDrop::new(sink).dst;
+
+ let src = unsafe { iterator.as_inner().as_into_iter() };
+ // check if SourceIter contract was upheld
+ // caveat: if they weren't we may not even make it to this point
+ debug_assert_eq!(src_buf, src.buf.as_ptr());
+ // check InPlaceIterable contract. This is only possible if the iterator advanced the
+ // source pointer at all. If it uses unchecked access via TrustedRandomAccess
+ // then the source pointer will stay in its initial position and we can't use it as reference
+ if src.ptr != src_ptr {
+ debug_assert!(
+ dst as *const _ <= src.ptr,
+ "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
+ );
+ }
+
+ // drop any remaining values at the tail of the source
+ src.drop_remaining();
+ // but prevent drop of the allocation itself once IntoIter goes out of scope
+ src.forget_allocation();
+
+ let vec = unsafe {
+ let len = dst.offset_from(dst_buf) as usize;
+ Vec::from_raw_parts(dst_buf, len, cap)
+ };
+
+ vec
+ }
+}
+
+fn write_in_place_with_drop<T>(
+ src_end: *const T,
+) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
+ move |mut sink, item| {
+ unsafe {
+ // the InPlaceIterable contract cannot be verified precisely here since
+ // try_fold has an exclusive reference to the source pointer
+ // all we can do is check if it's still in range
+ debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
+ ptr::write(sink.dst, item);
+ sink.dst = sink.dst.add(1);
+ }
+ Ok(sink)
+ }
+}
--- /dev/null
+use crate::alloc::Allocator;
+use core::iter::TrustedLen;
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::{IntoIter, SetLenOnDrop, Vec};
+
+// Specialization trait used for Vec::extend
+pub(super) trait SpecExtend<T, I> {
+ fn spec_extend(&mut self, iter: I);
+}
+
+impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
+where
+ I: Iterator<Item = T>,
+{
+ default fn spec_extend(&mut self, iter: I) {
+ self.extend_desugared(iter)
+ }
+}
+
+impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
+where
+ I: TrustedLen<Item = T>,
+{
+ default fn spec_extend(&mut self, iterator: I) {
+ // This is the case for a TrustedLen iterator.
+ let (low, high) = iterator.size_hint();
+ if let Some(high_value) = high {
+ debug_assert_eq!(
+ low,
+ high_value,
+ "TrustedLen iterator's size hint is not exact: {:?}",
+ (low, high)
+ );
+ }
+ if let Some(additional) = high {
+ self.reserve(additional);
+ unsafe {
+ let mut ptr = self.as_mut_ptr().add(self.len());
+ let mut local_len = SetLenOnDrop::new(&mut self.len);
+ iterator.for_each(move |element| {
+ ptr::write(ptr, element);
+ ptr = ptr.offset(1);
+ // NB can't overflow since we would have had to alloc the address space
+ local_len.increment_len(1);
+ });
+ }
+ } else {
+ self.extend_desugared(iterator)
+ }
+ }
+}
+
+impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
+ fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
+ unsafe {
+ self.append_elements(iterator.as_slice() as _);
+ }
+ iterator.ptr = iterator.end;
+ }
+}
+
+impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
+where
+ I: Iterator<Item = &'a T>,
+ T: Clone,
+{
+ default fn spec_extend(&mut self, iterator: I) {
+ self.spec_extend(iterator.cloned())
+ }
+}
+
+impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
+where
+ T: Copy,
+{
+ fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
+ let slice = iterator.as_slice();
+ unsafe { self.append_elements(slice) };
+ }
+}
--- /dev/null
+use crate::alloc::Allocator;
+use crate::raw_vec::RawVec;
+use core::ptr::{self};
+
+use super::{ExtendElement, IsZero, Vec};
+
+// Specialization trait used for Vec::from_elem
+pub(super) trait SpecFromElem: Sized {
+ fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A>;
+}
+
+impl<T: Clone> SpecFromElem for T {
+ default fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A> {
+ let mut v = Vec::with_capacity_in(n, alloc);
+ v.extend_with(n, ExtendElement(elem));
+ v
+ }
+}
+
+impl SpecFromElem for i8 {
+ #[inline]
+ fn from_elem<A: Allocator>(elem: i8, n: usize, alloc: A) -> Vec<i8, A> {
+ if elem == 0 {
+ return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
+ }
+ unsafe {
+ let mut v = Vec::with_capacity_in(n, alloc);
+ ptr::write_bytes(v.as_mut_ptr(), elem as u8, n);
+ v.set_len(n);
+ v
+ }
+ }
+}
+
+impl SpecFromElem for u8 {
+ #[inline]
+ fn from_elem<A: Allocator>(elem: u8, n: usize, alloc: A) -> Vec<u8, A> {
+ if elem == 0 {
+ return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
+ }
+ unsafe {
+ let mut v = Vec::with_capacity_in(n, alloc);
+ ptr::write_bytes(v.as_mut_ptr(), elem, n);
+ v.set_len(n);
+ v
+ }
+ }
+}
+
+impl<T: Clone + IsZero> SpecFromElem for T {
+ #[inline]
+ fn from_elem<A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
+ if elem.is_zero() {
+ return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
+ }
+ let mut v = Vec::with_capacity_in(n, alloc);
+ v.extend_with(n, ExtendElement(elem));
+ v
+ }
+}
--- /dev/null
+use core::mem::ManuallyDrop;
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec};
+
+/// Specialization trait used for Vec::from_iter
+///
+/// ## The delegation graph:
+///
+/// ```text
+/// +-------------+
+/// |FromIterator |
+/// +-+-----------+
+/// |
+/// v
+/// +-+-------------------------------+ +---------------------+
+/// |SpecFromIter +---->+SpecFromIterNested |
+/// |where I: | | |where I: |
+/// | Iterator (default)----------+ | | Iterator (default) |
+/// | vec::IntoIter | | | TrustedLen |
+/// | SourceIterMarker---fallback-+ | | |
+/// | slice::Iter | | |
+/// | Iterator<Item = &Clone> | +---------------------+
+/// +---------------------------------+
+/// ```
+pub(super) trait SpecFromIter<T, I> {
+ fn from_iter(iter: I) -> Self;
+}
+
+impl<T, I> SpecFromIter<T, I> for Vec<T>
+where
+ I: Iterator<Item = T>,
+{
+ default fn from_iter(iterator: I) -> Self {
+ SpecFromIterNested::from_iter(iterator)
+ }
+}
+
+impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
+ fn from_iter(iterator: IntoIter<T>) -> Self {
+ // A common case is passing a vector into a function which immediately
+ // re-collects into a vector. We can short circuit this if the IntoIter
+ // has not been advanced at all.
+ // When it has been advanced We can also reuse the memory and move the data to the front.
+ // But we only do so when the resulting Vec wouldn't have more unused capacity
+ // than creating it through the generic FromIterator implementation would. That limitation
+ // is not strictly necessary as Vec's allocation behavior is intentionally unspecified.
+ // But it is a conservative choice.
+ let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr;
+ if !has_advanced || iterator.len() >= iterator.cap / 2 {
+ unsafe {
+ let it = ManuallyDrop::new(iterator);
+ if has_advanced {
+ ptr::copy(it.ptr, it.buf.as_ptr(), it.len());
+ }
+ return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap);
+ }
+ }
+
+ let mut vec = Vec::new();
+ // must delegate to spec_extend() since extend() itself delegates
+ // to spec_from for empty Vecs
+ vec.spec_extend(iterator);
+ vec
+ }
+}
+
+impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
+where
+ I: Iterator<Item = &'a T>,
+ T: Clone,
+{
+ default fn from_iter(iterator: I) -> Self {
+ SpecFromIter::from_iter(iterator.cloned())
+ }
+}
+
+// This utilizes `iterator.as_slice().to_vec()` since spec_extend
+// must take more steps to reason about the final capacity + length
+// and thus do more work. `to_vec()` directly allocates the correct amount
+// and fills it exactly.
+impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
+ #[cfg(not(test))]
+ fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
+ iterator.as_slice().to_vec()
+ }
+
+ // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
+ // required for this method definition, is not available. Instead use the
+ // `slice::to_vec` function which is only available with cfg(test)
+ // NB see the slice::hack module in slice.rs for more information
+ #[cfg(test)]
+ fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
+ crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global)
+ }
+}
--- /dev/null
+use core::iter::TrustedLen;
+use core::ptr::{self};
+
+use super::{SpecExtend, Vec};
+
+/// Another specialization trait for Vec::from_iter
+/// necessary to manually prioritize overlapping specializations
+/// see [`SpecFromIter`] for details.
+pub(super) trait SpecFromIterNested<T, I> {
+ fn from_iter(iter: I) -> Self;
+}
+
+impl<T, I> SpecFromIterNested<T, I> for Vec<T>
+where
+ I: Iterator<Item = T>,
+{
+ default fn from_iter(mut iterator: I) -> Self {
+ // Unroll the first iteration, as the vector is going to be
+ // expanded on this iteration in every case when the iterable is not
+ // empty, but the loop in extend_desugared() is not going to see the
+ // vector being full in the few subsequent loop iterations.
+ // So we get better branch prediction.
+ let mut vector = match iterator.next() {
+ None => return Vec::new(),
+ Some(element) => {
+ let (lower, _) = iterator.size_hint();
+ let mut vector = Vec::with_capacity(lower.saturating_add(1));
+ unsafe {
+ ptr::write(vector.as_mut_ptr(), element);
+ vector.set_len(1);
+ }
+ vector
+ }
+ };
+ // must delegate to spec_extend() since extend() itself delegates
+ // to spec_from for empty Vecs
+ <Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
+ vector
+ }
+}
+
+impl<T, I> SpecFromIterNested<T, I> for Vec<T>
+where
+ I: TrustedLen<Item = T>,
+{
+ fn from_iter(iterator: I) -> Self {
+ let mut vector = match iterator.size_hint() {
+ (_, Some(upper)) => Vec::with_capacity(upper),
+ _ => Vec::new(),
+ };
+ // must delegate to spec_extend() since extend() itself delegates
+ // to spec_from for empty Vecs
+ vector.spec_extend(iterator);
+ vector
+ }
+}
--- /dev/null
+use crate::alloc::{Allocator, Global};
+use core::ptr::{self};
+use core::slice::{self};
+
+use super::{Drain, Vec};
+
+/// A splicing iterator for `Vec`.
+///
+/// This struct is created by [`Vec::splice()`].
+/// See its documentation for more.
+///
+/// # Example
+///
+/// ```
+/// let mut v = vec![0, 1, 2];
+/// let new = [7, 8];
+/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
+/// ```
+#[derive(Debug)]
+#[stable(feature = "vec_splice", since = "1.21.0")]
+pub struct Splice<
+ 'a,
+ I: Iterator + 'a,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
+> {
+ pub(super) drain: Drain<'a, I::Item, A>,
+ pub(super) replace_with: I,
+}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.drain.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.drain.size_hint()
+ }
+}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.drain.next_back()
+ }
+}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
+
+#[stable(feature = "vec_splice", since = "1.21.0")]
+impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
+ fn drop(&mut self) {
+ self.drain.by_ref().for_each(drop);
+
+ unsafe {
+ if self.drain.tail_len == 0 {
+ self.drain.vec.as_mut().extend(self.replace_with.by_ref());
+ return;
+ }
+
+ // First fill the range left by drain().
+ if !self.drain.fill(&mut self.replace_with) {
+ return;
+ }
+
+ // There may be more elements. Use the lower bound as an estimate.
+ // FIXME: Is the upper bound a better guess? Or something else?
+ let (lower_bound, _upper_bound) = self.replace_with.size_hint();
+ if lower_bound > 0 {
+ self.drain.move_tail(lower_bound);
+ if !self.drain.fill(&mut self.replace_with) {
+ return;
+ }
+ }
+
+ // Collect any remaining elements.
+ // This is a zero-length vector which does not allocate if `lower_bound` was exact.
+ let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
+ // Now we have an exact count.
+ if collected.len() > 0 {
+ self.drain.move_tail(collected.len());
+ let filled = self.drain.fill(&mut collected);
+ debug_assert!(filled);
+ debug_assert_eq!(collected.len(), 0);
+ }
+ }
+ // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
+ }
+}
+
+/// Private helper methods for `Splice::drop`
+impl<T, A: Allocator> Drain<'_, T, A> {
+ /// The range from `self.vec.len` to `self.tail_start` contains elements
+ /// that have been moved out.
+ /// Fill that range as much as possible with new elements from the `replace_with` iterator.
+ /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
+ unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
+ let vec = unsafe { self.vec.as_mut() };
+ let range_start = vec.len;
+ let range_end = self.tail_start;
+ let range_slice = unsafe {
+ slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
+ };
+
+ for place in range_slice {
+ if let Some(new_item) = replace_with.next() {
+ unsafe { ptr::write(place, new_item) };
+ vec.len += 1;
+ } else {
+ return false;
+ }
+ }
+ true
+ }
+
+ /// Makes room for inserting more elements before the tail.
+ unsafe fn move_tail(&mut self, additional: usize) {
+ let vec = unsafe { self.vec.as_mut() };
+ let len = self.tail_start + self.tail_len;
+ vec.buf.reserve(len, additional);
+
+ let new_tail_start = self.tail_start + additional;
+ unsafe {
+ let src = vec.as_ptr().add(self.tail_start);
+ let dst = vec.as_mut_ptr().add(new_tail_start);
+ ptr::copy(src, dst, self.tail_len);
+ }
+ self.tail_start = new_tail_start;
+ }
+}
#![feature(slice_ptr_get)]
#![feature(split_inclusive)]
#![feature(binary_heap_retain)]
-#![feature(deque_range)]
#![feature(inplace_iteration)]
#![feature(iter_map_while)]
#![feature(int_bits_const)]
/// * `Layout` queries and calculations in general must be correct. Callers of
/// this trait are allowed to rely on the contracts defined on each method,
/// and implementors must ensure such contracts remain true.
+///
+/// * You may not rely on allocations actually happening, even if there are explicit
+/// heap allocations in the source. The optimizer may detect unused allocations that it can either
+/// eliminate entirely or move to the stack and thus never invoke the allocator. The
+/// optimizer may further assume that allocation is infallible, so code that used to fail due
+/// to allocator failures may now suddenly work because the optimizer worked around the
+/// need for an allocation. More concretely, the following code example is unsound, irrespective
+/// of whether your custom allocator allows counting how many allocations have happened.
+///
+/// ```rust,ignore (unsound and has placeholders)
+/// drop(Box::new(42));
+/// let number_of_heap_allocs = /* call private allocator API */;
+/// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); }
+/// ```
+///
+/// Note that the optimizations mentioned above are not the only
+/// optimization that can be applied. You may generally not rely on heap allocations
+/// happening if they can be removed without changing program behavior.
+/// Whether allocations happen or not is not part of the program behavior, even if it
+/// could be detected via an allocator that tracks allocations by printing or otherwise
+/// having side effects.
#[stable(feature = "global_alloc", since = "1.28.0")]
pub unsafe trait GlobalAlloc {
/// Allocate memory as described by the given `layout`.
unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) }
}
+ /// 'Zips up' two arrays into a single array of pairs.
+ ///
+ /// `zip()` returns a new array where every element is a tuple where the
+ /// first element comes from the first array, and the second element comes
+ /// from the second array. In other words, it zips two arrays together,
+ /// into a single one.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(array_zip)]
+ /// let x = [1, 2, 3];
+ /// let y = [4, 5, 6];
+ /// let z = x.zip(y);
+ /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]);
+ /// ```
+ #[unstable(feature = "array_zip", issue = "80094")]
+ pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
+ use crate::mem::MaybeUninit;
+
+ let mut dst = MaybeUninit::uninit_array::<N>();
+ for (i, (lhs, rhs)) in IntoIter::new(self).zip(IntoIter::new(rhs)).enumerate() {
+ dst[i].write((lhs, rhs));
+ }
+ // FIXME: Convert to crate::mem::transmute once it works with generics.
+ // unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst) }
+ // SAFETY: At this point we've properly initialized the whole array
+ // and we just need to cast it to the correct type.
+ unsafe { crate::mem::transmute_copy::<_, [(T, U); N]>(&dst) }
+ }
+
/// Returns a slice containing the entire array. Equivalent to `&s[..]`.
#[unstable(feature = "array_methods", issue = "76118")]
pub fn as_slice(&self) -> &[T] {
///
/// assert_eq!(None, c);
/// ```
+#[doc(alias = "chr")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_u32(i: u32) -> Option<char> {
/// Allocate at compile time. Should not be called at runtime.
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
- #[cfg(not(bootstrap))]
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
}
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
#[doc(alias = "memcpy")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
#[inline]
-pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
- if cfg!(debug_assertions)
+ // FIXME: Perform these checks only at run time
+ /*if cfg!(debug_assertions)
&& !(is_aligned_and_not_null(src)
&& is_aligned_and_not_null(dst)
&& is_nonoverlapping(src, dst, count))
{
// Not panicking to keep codegen impact smaller.
abort();
- }
+ }*/
// SAFETY: the safety contract for `copy_nonoverlapping` must be
// upheld by the caller.
/// ```
#[doc(alias = "memmove")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
#[inline]
-pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
+ #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")]
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
- if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
+ // FIXME: Perform these checks only at run time
+ /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
// Not panicking to keep codegen impact smaller.
abort();
- }
+ }*/
// SAFETY: the safety contract for `copy` must be upheld by the caller.
unsafe { copy(src, dst, count) }
--- /dev/null
+use super::Peekable;
+
+/// An iterator adapter that places a separator between all elements.
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+#[derive(Debug, Clone)]
+pub struct Intersperse<I: Iterator>
+where
+ I::Item: Clone,
+{
+ separator: I::Item,
+ iter: Peekable<I>,
+ needs_sep: bool,
+}
+
+impl<I: Iterator> Intersperse<I>
+where
+ I::Item: Clone,
+{
+ pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
+ Self { iter: iter.peekable(), separator, needs_sep: false }
+ }
+}
+
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+impl<I> Iterator for Intersperse<I>
+where
+ I: Iterator,
+ I::Item: Clone,
+{
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<I::Item> {
+ if self.needs_sep && self.iter.peek().is_some() {
+ self.needs_sep = false;
+ Some(self.separator.clone())
+ } else {
+ self.needs_sep = true;
+ self.iter.next()
+ }
+ }
+
+ fn fold<B, F>(mut self, init: B, mut f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let mut accum = init;
+
+ // Use `peek()` first to avoid calling `next()` on an empty iterator.
+ if !self.needs_sep || self.iter.peek().is_some() {
+ if let Some(x) = self.iter.next() {
+ accum = f(accum, x);
+ }
+ }
+
+ let element = &self.separator;
+
+ self.iter.fold(accum, |mut accum, x| {
+ accum = f(accum, element.clone());
+ accum = f(accum, x);
+ accum
+ })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (lo, hi) = self.iter.size_hint();
+ let next_is_elem = !self.needs_sep;
+ let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
+ let hi = match hi {
+ Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
+ None => None,
+ };
+ (lo, hi)
+ }
+}
mod flatten;
mod fuse;
mod inspect;
+mod intersperse;
mod map;
mod map_while;
mod peekable;
#[stable(feature = "iter_copied", since = "1.36.0")]
pub use self::copied::Copied;
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+pub use self::intersperse::Intersperse;
+
#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
pub use self::map_while::MapWhile;
pub use self::adapters::Copied;
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub use self::adapters::Flatten;
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+pub use self::adapters::Intersperse;
#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
pub use self::adapters::MapWhile;
#[unstable(feature = "inplace_iteration", issue = "none")]
///
/// assert_eq!(5, five.len());
/// ```
+ #[doc(alias = "length")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn len(&self) -> usize {
use super::super::TrustedRandomAccess;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
use super::super::{FlatMap, Flatten};
-use super::super::{FromIterator, Product, Sum, Zip};
+use super::super::{FromIterator, Intersperse, Product, Sum, Zip};
use super::super::{
Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
};
Zip::new(self, other.into_iter())
}
+ /// Places a copy of `separator` between all elements.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(iter_intersperse)]
+ ///
+ /// let hello = ["Hello", "World"].iter().copied().intersperse(" ").collect::<String>();
+ /// assert_eq!(hello, "Hello World");
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+ fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
+ where
+ Self: Sized,
+ Self::Item: Clone,
+ {
+ Intersperse::new(self, separator)
+ }
+
/// Takes a closure and creates an iterator which calls that closure on each
/// element.
///
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(cfg_target_has_atomic)]
-#![cfg_attr(not(bootstrap), feature(const_heap))]
+#![feature(const_heap)]
#![feature(const_alloc_layout)]
#![feature(const_assert_type)]
#![feature(const_discriminant)]
#![feature(const_cell_into_inner)]
+#![feature(const_intrinsic_copy)]
#![feature(const_checked_int_methods)]
#![feature(const_euclidean_int_methods)]
#![feature(const_float_classify)]
#![feature(const_precise_live_drops)]
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
+#![feature(const_ptr_read)]
#![feature(const_raw_ptr_comparison)]
#![feature(const_raw_ptr_deref)]
#![feature(const_slice_from_raw_parts)]
#![feature(doc_spotlight)]
#![feature(duration_consts_2)]
#![feature(duration_saturating_ops)]
+#![feature(extended_key_value_attributes)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
#![feature(nll)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![feature(or_patterns)]
#![feature(prelude_import)]
#![feature(repr_simd, platform_intrinsics)]
#[macro_export]
#[allow_internal_unstable(core_panic, const_caller_location)]
#[stable(feature = "core", since = "1.6.0")]
-#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "core_panic_macro")]
+#[rustc_diagnostic_item = "core_panic_macro"]
macro_rules! panic {
() => (
$crate::panic!("explicit panic")
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "debug_assert_macro")]
+#[rustc_diagnostic_item = "debug_assert_macro"]
macro_rules! debug_assert {
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert!($($arg)*); })
}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
- #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "assert_macro")]
+ #[rustc_diagnostic_item = "assert_macro"]
#[allow_internal_unstable(core_panic)]
macro_rules! assert {
($cond:expr $(,)?) => {{ /* compiler built-in */ }};
/// // they both get dropped!
/// ```
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
+ #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
#[inline(always)]
- pub unsafe fn assume_init_read(&self) -> T {
+ pub const unsafe fn assume_init_read(&self) -> T {
// SAFETY: the caller must guarantee that `self` is initialized.
// Reading from `self.as_ptr()` is safe since `self` should be initialized.
unsafe {
#[inline]
#[unstable(feature = "forget_unsized", issue = "none")]
pub fn forget_unsized<T: ?Sized>(t: T) {
+ #[cfg(bootstrap)]
// SAFETY: the forget intrinsic could be safe, but there's no point in making it safe since
// we'll be implementing this function soon via `ManuallyDrop`
- unsafe { intrinsics::forget(t) }
+ unsafe {
+ intrinsics::forget(t)
+ }
+ #[cfg(not(bootstrap))]
+ intrinsics::forget(t)
}
/// Returns the size of a type in bytes.
/// ```
#[inline]
#[unstable(feature = "layout_for_ptr", issue = "69835")]
-pub unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
+#[rustc_const_unstable(feature = "const_size_of_val_raw", issue = "46571")]
+pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
intrinsics::size_of_val(val)
}
/// ```
#[inline]
#[unstable(feature = "layout_for_ptr", issue = "69835")]
-pub unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
+#[rustc_const_unstable(feature = "const_align_of_val_raw", issue = "46571")]
+pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
intrinsics::min_align_of_val(val)
}
macro_rules! int_impl {
- ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr,
- $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
+ ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr,
+ $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
- doc_comment! {
- concat!("The smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
- }
-
- doc_comment! {
- concat!("The largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MAX: Self = !Self::MIN;
- }
-
- doc_comment! {
- concat!("The size of this integer type in bits.
-
-# Examples
-
-```
-", $Feature, "#![feature(int_bits_const)]
-assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");",
-$EndFeature, "
-```"),
- #[unstable(feature = "int_bits_const", issue = "76904")]
- pub const BITS: u32 = $BITS;
- }
-
- doc_comment! {
- concat!("Converts a string slice in a given base to an integer.
-
-The string is expected to be an optional `+` or `-` sign followed by digits.
-Leading and trailing whitespace represent an error. Digits are a subset of these characters,
-depending on `radix`:
-
- * `0-9`
- * `a-z`
- * `A-Z`
-
-# Panics
-
-This function panics if `radix` is not in the range from 2 to 36.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
- from_str_radix(src, radix)
- }
- }
-
- doc_comment! {
- concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b100_0000", stringify!($SelfT), ";
-
-assert_eq!(n.count_ones(), 1);",
-$EndFeature, "
-```
-"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[doc(alias = "popcount")]
- #[doc(alias = "popcnt")]
- #[inline]
- pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
- }
-
- doc_comment! {
- concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn count_zeros(self) -> u32 {
- (!self).count_ones()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -1", stringify!($SelfT), ";
-
-assert_eq!(n.leading_zeros(), 0);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn leading_zeros(self) -> u32 {
- (self as $UnsignedT).leading_zeros()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of trailing zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -4", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_zeros(), 2);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn trailing_zeros(self) -> u32 {
- (self as $UnsignedT).trailing_zeros()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of leading ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = -1", stringify!($SelfT), ";
-
-assert_eq!(n.leading_ones(), ", stringify!($BITS), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn leading_ones(self) -> u32 {
- (self as $UnsignedT).leading_ones()
- }
- }
-
- doc_comment! {
- concat!("Returns the number of trailing ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 3", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_ones(), 2);",
-$EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn trailing_ones(self) -> u32 {
- (self as $UnsignedT).trailing_ones()
- }
- }
-
- doc_comment! {
- concat!("Shifts the bits to the left by a specified amount, `n`,
-wrapping the truncated bits to the end of the resulting integer.
-
-Please note this isn't the same operation as the `<<` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_op, stringify!($SelfT), ";
-let m = ", $rot_result, ";
-
-assert_eq!(n.rotate_left(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_left(self, n: u32) -> Self {
- (self as $UnsignedT).rotate_left(n) as Self
- }
- }
-
- doc_comment! {
- concat!("Shifts the bits to the right by a specified amount, `n`,
-wrapping the truncated bits to the beginning of the resulting
-integer.
-
-Please note this isn't the same operation as the `>>` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_result, stringify!($SelfT), ";
-let m = ", $rot_op, ";
-
-assert_eq!(n.rotate_right(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_right(self, n: u32) -> Self {
- (self as $UnsignedT).rotate_right(n) as Self
- }
- }
-
- doc_comment! {
- concat!("Reverses the byte order of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-
-let m = n.swap_bytes();
-
-assert_eq!(m, ", $swapped, ");
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn swap_bytes(self) -> Self {
- (self as $UnsignedT).swap_bytes() as Self
- }
- }
-
- doc_comment! {
- concat!("Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
- second least-significant bit becomes second most-significant bit, etc.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.reverse_bits();
-
-assert_eq!(m, ", $reversed, ");
-assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());
-```"),
- #[stable(feature = "reverse_bits", since = "1.37.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- #[must_use]
- pub const fn reverse_bits(self) -> Self {
- (self as $UnsignedT).reverse_bits() as Self
- }
- }
-
- doc_comment! {
- concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn from_be(x: Self) -> Self {
- #[cfg(target_endian = "big")]
- {
- x
- }
- #[cfg(not(target_endian = "big"))]
- {
- x.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn from_le(x: Self) -> Self {
- #[cfg(target_endian = "little")]
- {
- x
- }
- #[cfg(not(target_endian = "little"))]
- {
- x.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(n.to_be(), n)
-} else {
- assert_eq!(n.to_be(), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn to_be(self) -> Self { // or not to be?
- #[cfg(target_endian = "big")]
- {
- self
- }
- #[cfg(not(target_endian = "big"))]
- {
- self.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(n.to_le(), n)
-} else {
- assert_eq!(n.to_le(), n.swap_bytes())
-}",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
- #[inline]
- pub const fn to_le(self) -> Self {
- #[cfg(target_endian = "little")]
- {
- self
- }
- #[cfg(not(target_endian = "little"))]
- {
- self.swap_bytes()
- }
- }
- }
-
- doc_comment! {
- concat!("Checked integer addition. Computes `self + rhs`, returning `None`
-if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1));
-assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_add(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_add(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
-"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_add`.
- unsafe { intrinsics::unchecked_add(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1));
-assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_sub(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
-"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_sub`.
- unsafe { intrinsics::unchecked_sub(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT),
-"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_mul(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
-"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_mul`.
- unsafe { intrinsics::unchecked_mul(self, rhs) }
- }
- }
-
- doc_comment! {
- concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
-or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT),
-"::MIN + 1).checked_div(-1), Some(", stringify!($Max), "));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None);
-assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- // SAFETY: div by zero and by INT_MIN have been checked above
- Some(unsafe { intrinsics::unchecked_div(self, rhs) })
- }
- }
- }
-
- doc_comment! {
- concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`,
-returning `None` if `rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!((", stringify!($SelfT),
-"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), "));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None);
-assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- Some(self.div_euclid(rhs))
- }
- }
- }
-
- doc_comment! {
- concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if
-`rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);
-assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- // SAFETY: div by zero and by INT_MIN have been checked above
- Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
- }
- }
- }
-
- doc_comment! {
- concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None`
-if `rhs == 0` or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
-assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
- None
- } else {
- Some(self.rem_euclid(rhs))
- }
- }
- }
-
- doc_comment! {
- concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn checked_neg(self) -> Option<Self> {
- let (a, b) = self.overflowing_neg();
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
-than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
-assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shl(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
-larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shr(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
- }
-
- doc_comment! {
- concat!("Checked absolute value. Computes `self.abs()`, returning `None` if
-`self == MIN`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));
-assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_abs", since = "1.13.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn checked_abs(self) -> Option<Self> {
- if self.is_negative() {
- self.checked_neg()
- } else {
- Some(self)
- }
- }
- }
-
- doc_comment! {
- concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
-overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
- if exp == 0 {
- return Some(1);
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = try_opt!(acc.checked_mul(base));
- }
- exp /= 2;
- base = try_opt!(base.checked_mul(base));
- }
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- Some(try_opt!(acc.checked_mul(base)))
- }
- }
-
- doc_comment! {
- concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric
-bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT),
-"::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT),
-"::MIN);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_add(self, rhs: Self) -> Self {
- intrinsics::saturating_add(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the
-numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT),
-"::MIN);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT),
-"::MAX);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_sub(self, rhs: Self) -> Self {
- intrinsics::saturating_sub(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
-instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100);
-assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT),
-"::MAX);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT),
-"::MIN + 1);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "saturating_neg", since = "1.45.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_neg(self) -> Self {
- intrinsics::saturating_sub(0, self)
- }
- }
-
- doc_comment! {
- concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self ==
-MIN` instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100);
-assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT),
-"::MAX);
-assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT),
-"::MAX);",
-$EndFeature, "
-```"),
-
- #[stable(feature = "saturating_neg", since = "1.45.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_abs(self) -> Self {
- if self.is_negative() {
- self.saturating_neg()
- } else {
- self
- }
- }
- }
-
- doc_comment! {
- concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the
-numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_mul(self, rhs: Self) -> Self {
- match self.checked_mul(rhs) {
- Some(x) => x,
- None => if (self < 0) == (rhs < 0) {
- Self::MAX
- } else {
- Self::MIN
- }
- }
- }
- }
-
- doc_comment! {
- concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);
-assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_pow(self, exp: u32) -> Self {
- match self.checked_pow(exp) {
- Some(x) => x,
- None if self < 0 && exp % 2 == 1 => Self::MIN,
- None => Self::MAX,
- }
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
-boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127);
-assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT),
-"::MIN + 1);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_add(self, rhs: Self) -> Self {
- intrinsics::wrapping_add(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
-boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127);
-assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ",
-stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_sub(self, rhs: Self) -> Self {
- intrinsics::wrapping_sub(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
-the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120);
-assert_eq!(11i8.wrapping_mul(12), -124);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_mul(self, rhs: Self) -> Self {
- intrinsics::wrapping_mul(self, rhs)
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the
-boundary of the type.
-
-The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where
-`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value
-that is too large to represent in the type. In such a case, this function returns `MIN` itself.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);
-assert_eq!((-128i8).wrapping_div(-1), -128);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div(self, rhs: Self) -> Self {
- self.overflowing_div(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`,
-wrapping around at the boundary of the type.
-
-Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value
-for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the
-type. In this case, this method returns `MIN` itself.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
-assert_eq!((-128i8).wrapping_div_euclid(-1), -128);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
- self.overflowing_div_euclid(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the
-boundary of the type.
-
-Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y`
-invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case,
-this function returns `0`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);
-assert_eq!((-128i8).wrapping_rem(-1), 0);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem(self, rhs: Self) -> Self {
- self.overflowing_rem(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around
-at the boundary of the type.
-
-Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value
-for the type). In this case, this method returns 0.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
-assert_eq!((-128i8).wrapping_rem_euclid(-1), 0);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
- self.overflowing_rem_euclid(rhs).0
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
-of the type.
-
-The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN`
-is the negative minimal value for the type); this is a positive value that is too large to represent
-in the type. In such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);
-assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT),
-"::MIN);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn wrapping_neg(self) -> Self {
- self.overflowing_neg().0
- }
- }
-
- doc_comment! {
- concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
-any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
-the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
-The primitive integer types all implement a [`rotate_left`](#method.rotate_left) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128);
-assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shl(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
- }
- }
- }
-
- doc_comment! {
- concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`
-removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
-to the range of the type, rather than the bits shifted out of the LHS being returned to the other
-end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1);
-assert_eq!((-128i16).wrapping_shr(64), -128);",
-$EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shr(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
- }
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at
-the boundary of the type.
-
-The only case where such wrapping can occur is when one takes the absolute value of the negative
-minimal value for the type; this is a positive value that is too large to represent in the type. In
-such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100);
-assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100);
-assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT),
-"::MIN);
-assert_eq!((-128i8).wrapping_abs() as u8, 128);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_abs", since = "1.13.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[allow(unused_attributes)]
- #[inline]
- pub const fn wrapping_abs(self) -> Self {
- if self.is_negative() {
- self.wrapping_neg()
- } else {
- self
- }
- }
- }
-
- doc_comment! {
- concat!("Computes the absolute value of `self` without any wrapping
-or panicking.
-
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "#![feature(unsigned_abs)]
-assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");
-assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");
-assert_eq!((-128i8).unsigned_abs(), 128u8);",
-$EndFeature, "
-```"),
- #[unstable(feature = "unsigned_abs", issue = "74913")]
- #[inline]
- pub const fn unsigned_abs(self) -> $UnsignedT {
- self.wrapping_abs() as $UnsignedT
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);
-assert_eq!(3i8.wrapping_pow(5), -13);
-assert_eq!(3i8.wrapping_pow(6), -39);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_pow(self, mut exp: u32) -> Self {
- if exp == 0 {
- return 1;
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = acc.wrapping_mul(base);
- }
- exp /= 2;
- base = base.wrapping_mul(base);
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- acc.wrapping_mul(base)
- }
- }
-
- doc_comment! {
- concat!("Calculates `self` + `rhs`
-
-Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
-assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT),
-"::MIN, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- doc_comment! {
- concat!("Calculates `self` - `rhs`
-
-Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
-would occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT),
-"::MAX, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- doc_comment! {
- concat!("Calculates the multiplication of `self` and `rhs`.
-
-Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
-would occur. If an overflow would have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false));
-assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
- }
-
- doc_comment! {
- concat!("Calculates the divisor when `self` is divided by `rhs`.
-
-Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would occur then self is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT),
-"::MIN, true));",
-$EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (self, true)
- } else {
- (self / rhs, false)
- }
- }
- }
-
- doc_comment! {
- concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
-
-Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
-occur. If an overflow would occur then `self` is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT),
-"::MIN, true));
-```"),
- #[inline]
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (self, true)
- } else {
- (self.div_euclid(rhs), false)
- }
- }
- }
-
- doc_comment! {
- concat!("Calculates the remainder when `self` is divided by `rhs`.
-
-Returns a tuple of the remainder after dividing along with a boolean indicating whether an
-arithmetic overflow would occur. If an overflow would occur then 0 is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));",
-$EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (0, true)
- } else {
- (self % rhs, false)
- }
- }
- }
-
-
- doc_comment! {
- concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`.
-
-Returns a tuple of the remainder after dividing along with a boolean indicating whether an
-arithmetic overflow would occur. If an overflow would occur then 0 is returned.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true));
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
- if unlikely!(self == Self::MIN && rhs == -1) {
- (0, true)
- } else {
- (self.rem_euclid(rhs), false)
+ /// The smallest value that can be represented by this integer type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");")]
+ /// ```
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
+
+ /// The largest value that can be represented by this integer type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");")]
+ /// ```
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MAX: Self = !Self::MIN;
+
+ /// The size of this integer type in bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(int_bits_const)]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
+ /// ```
+ #[unstable(feature = "int_bits_const", issue = "76904")]
+ pub const BITS: u32 = $BITS;
+
+ /// Converts a string slice in a given base to an integer.
+ ///
+ /// The string is expected to be an optional `+` or `-` sign followed by digits.
+ /// Leading and trailing whitespace represent an error. Digits are a subset of these characters,
+ /// depending on `radix`:
+ ///
+ /// * `0-9`
+ /// * `a-z`
+ /// * `A-Z`
+ ///
+ /// # Panics
+ ///
+ /// This function panics if `radix` is not in the range from 2 to 36.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ from_str_radix(src, radix)
+ }
+
+ /// Returns the number of ones in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0b100_0000", stringify!($SelfT), ";")]
+ ///
+ /// assert_eq!(n.count_ones(), 1);
+ /// ```
+ ///
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[doc(alias = "popcount")]
+ #[doc(alias = "popcnt")]
+ #[inline]
+ pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
+
+ /// Returns the number of zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn count_zeros(self) -> u32 {
+ (!self).count_ones()
+ }
+
+ /// Returns the number of leading zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = -1", stringify!($SelfT), ";")]
+ ///
+ /// assert_eq!(n.leading_zeros(), 0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn leading_zeros(self) -> u32 {
+ (self as $UnsignedT).leading_zeros()
+ }
+
+ /// Returns the number of trailing zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = -4", stringify!($SelfT), ";")]
+ ///
+ /// assert_eq!(n.trailing_zeros(), 2);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn trailing_zeros(self) -> u32 {
+ (self as $UnsignedT).trailing_zeros()
+ }
+
+ /// Returns the number of leading ones in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = -1", stringify!($SelfT), ";")]
+ ///
+ #[doc = concat!("assert_eq!(n.leading_ones(), ", stringify!($BITS), ");")]
+ /// ```
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn leading_ones(self) -> u32 {
+ (self as $UnsignedT).leading_ones()
+ }
+
+ /// Returns the number of trailing ones in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 3", stringify!($SelfT), ";")]
+ ///
+ /// assert_eq!(n.trailing_ones(), 2);
+ /// ```
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn trailing_ones(self) -> u32 {
+ (self as $UnsignedT).trailing_ones()
+ }
+
+ /// Shifts the bits to the left by a specified amount, `n`,
+ /// wrapping the truncated bits to the end of the resulting integer.
+ ///
+ /// Please note this isn't the same operation as the `<<` shifting operator!
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $rot_op, stringify!($SelfT), ";")]
+ #[doc = concat!("let m = ", $rot_result, ";")]
+ ///
+ #[doc = concat!("assert_eq!(n.rotate_left(", $rot, "), m);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_left(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_left(n) as Self
+ }
+
+ /// Shifts the bits to the right by a specified amount, `n`,
+ /// wrapping the truncated bits to the beginning of the resulting
+ /// integer.
+ ///
+ /// Please note this isn't the same operation as the `>>` shifting operator!
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $rot_result, stringify!($SelfT), ";")]
+ #[doc = concat!("let m = ", $rot_op, ";")]
+ ///
+ #[doc = concat!("assert_eq!(n.rotate_right(", $rot, "), m);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_right(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_right(n) as Self
+ }
+
+ /// Reverses the byte order of the integer.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+ ///
+ /// let m = n.swap_bytes();
+ ///
+ #[doc = concat!("assert_eq!(m, ", $swapped, ");")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn swap_bytes(self) -> Self {
+ (self as $UnsignedT).swap_bytes() as Self
+ }
+
+ /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
+ /// second least-significant bit becomes second most-significant bit, etc.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+ /// let m = n.reverse_bits();
+ ///
+ #[doc = concat!("assert_eq!(m, ", $reversed, ");")]
+ #[doc = concat!("assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());")]
+ /// ```
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ #[must_use]
+ pub const fn reverse_bits(self) -> Self {
+ (self as $UnsignedT).reverse_bits() as Self
+ }
+
+ /// Converts an integer from big endian to the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_be(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())")]
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn from_be(x: Self) -> Self {
+ #[cfg(target_endian = "big")]
+ {
+ x
+ }
+ #[cfg(not(target_endian = "big"))]
+ {
+ x.swap_bytes()
+ }
+ }
+
+ /// Converts an integer from little endian to the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_le(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())")]
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn from_le(x: Self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ x
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ x.swap_bytes()
+ }
+ }
+
+ /// Converts `self` to big endian from the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ /// assert_eq!(n.to_be(), n)
+ /// } else {
+ /// assert_eq!(n.to_be(), n.swap_bytes())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn to_be(self) -> Self { // or not to be?
+ #[cfg(target_endian = "big")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "big"))]
+ {
+ self.swap_bytes()
+ }
+ }
+
+ /// Converts `self` to little endian from the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ /// assert_eq!(n.to_le(), n)
+ /// } else {
+ /// assert_eq!(n.to_le(), n.swap_bytes())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
+ #[inline]
+ pub const fn to_le(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ self.swap_bytes()
+ }
+ }
+
+ /// Checked integer addition. Computes `self + rhs`, returning `None`
+ /// if overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1));")]
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_add(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
+ /// cannot occur. This results in undefined behavior when
+ #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_add`.
+ unsafe { intrinsics::unchecked_add(self, rhs) }
+ }
+
+ /// Checked integer subtraction. Computes `self - rhs`, returning `None` if
+ /// overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1));")]
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_sub(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
+ /// cannot occur. This results in undefined behavior when
+ #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_sub`.
+ unsafe { intrinsics::unchecked_sub(self, rhs) }
+ }
+
+ /// Checked integer multiplication. Computes `self * rhs`, returning `None` if
+ /// overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_mul(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
+ /// cannot occur. This results in undefined behavior when
+ #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_mul`.
+ unsafe { intrinsics::unchecked_mul(self, rhs) }
+ }
+
+ /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
+ /// or the division results in overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_div(-1), Some(", stringify!($Max), "));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None);")]
+ #[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ // SAFETY: div by zero and by INT_MIN have been checked above
+ Some(unsafe { intrinsics::unchecked_div(self, rhs) })
+ }
+ }
+
+ /// Checked Euclidean division. Computes `self.div_euclid(rhs)`,
+ /// returning `None` if `rhs == 0` or the division results in overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), "));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None);")]
+ #[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None);")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ Some(self.div_euclid(rhs))
+ }
+ }
+
+ /// Checked integer remainder. Computes `self % rhs`, returning `None` if
+ /// `rhs == 0` or the division results in overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ // SAFETY: div by zero and by INT_MIN have been checked above
+ Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
+ }
+ }
+
+ /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None`
+ /// if `rhs == 0` or the division results in overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None);")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) {
+ None
+ } else {
+ Some(self.rem_euclid(rhs))
+ }
+ }
+
+ /// Checked negation. Computes `-self`, returning `None` if `self == MIN`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn checked_neg(self) -> Option<Self> {
+ let (a, b) = self.overflowing_neg();
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger
+ /// than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")]
+ #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shl(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
+ /// larger than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));")]
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shr(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Checked absolute value. Computes `self.abs()`, returning `None` if
+ /// `self == MIN`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);")]
+ /// ```
+ #[stable(feature = "no_panic_abs", since = "1.13.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn checked_abs(self) -> Option<Self> {
+ if self.is_negative() {
+ self.checked_neg()
+ } else {
+ Some(self)
+ }
+ }
+
+ /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
+ /// overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);")]
+ /// ```
+
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+ if exp == 0 {
+ return Some(1);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = try_opt!(acc.checked_mul(base));
}
- }
- }
-
-
- doc_comment! {
- concat!("Negates self, overflowing if this is equal to the minimum value.
-
-Returns a tuple of the negated version of self along with a boolean indicating whether an overflow
-happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the
-minimum value will be returned again and `true` will be returned for an overflow happening.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false));
-assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT),
-"::MIN, true));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[allow(unused_attributes)]
- pub const fn overflowing_neg(self) -> (Self, bool) {
- if unlikely!(self == Self::MIN) {
- (Self::MIN, true)
+ exp /= 2;
+ base = try_opt!(base.checked_mul(base));
+ }
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ Some(try_opt!(acc.checked_mul(base)))
+ }
+
+ /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric
+ /// bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), "::MAX);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), "::MIN);")]
+ /// ```
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_add(self, rhs: Self) -> Self {
+ intrinsics::saturating_add(self, rhs)
+ }
+
+ /// Saturating integer subtraction. Computes `self - rhs`, saturating at the
+ /// numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), "::MIN);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), "::MAX);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_sub(self, rhs: Self) -> Self {
+ intrinsics::saturating_sub(self, rhs)
+ }
+
+ /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
+ /// instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100);")]
+ #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), "::MAX);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), "::MIN + 1);")]
+ /// ```
+
+ #[stable(feature = "saturating_neg", since = "1.45.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_neg(self) -> Self {
+ intrinsics::saturating_sub(0, self)
+ }
+
+ /// Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self ==
+ /// MIN` instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100);")]
+ #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), "::MAX);")]
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), "::MAX);")]
+ /// ```
+
+ #[stable(feature = "saturating_neg", since = "1.45.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_abs(self) -> Self {
+ if self.is_negative() {
+ self.saturating_neg()
+ } else {
+ self
+ }
+ }
+
+ /// Saturating integer multiplication. Computes `self * rhs`, saturating at the
+ /// numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_mul(self, rhs: Self) -> Self {
+ match self.checked_mul(rhs) {
+ Some(x) => x,
+ None => if (self < 0) == (rhs < 0) {
+ Self::MAX
} else {
- (-self, false)
+ Self::MIN
}
}
}
- doc_comment! {
- concat!("Shifts self left by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
-value was larger than or equal to the number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));
-assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
- }
- }
-
- doc_comment! {
- concat!("Shifts self right by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
-value was larger than or equal to the number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
-assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
- }
- }
-
- doc_comment! {
- concat!("Computes the absolute value of `self`.
-
-Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow
-happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type
- ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned
-for an overflow happening.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false));
-assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false));
-assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT),
-"::MIN, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_abs", since = "1.13.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn overflowing_abs(self) -> (Self, bool) {
- (self.wrapping_abs(), self == Self::MIN)
- }
- }
-
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-Returns a tuple of the exponentiation along with a bool indicating
-whether an overflow happened.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));
-assert_eq!(3i8.overflowing_pow(5), (-13, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
- if exp == 0 {
- return (1,false);
+ /// Saturating integer exponentiation. Computes `self.pow(exp)`,
+ /// saturating at the numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);")]
+ /// ```
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_pow(self, exp: u32) -> Self {
+ match self.checked_pow(exp) {
+ Some(x) => x,
+ None if self < 0 && exp % 2 == 1 => Self::MIN,
+ None => Self::MAX,
+ }
+ }
+
+ /// Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
+ /// boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), "::MIN + 1);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_add(self, rhs: Self) -> Self {
+ intrinsics::wrapping_add(self, rhs)
+ }
+
+ /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
+ /// boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127);")]
+ #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", stringify!($SelfT), "::MAX);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_sub(self, rhs: Self) -> Self {
+ intrinsics::wrapping_sub(self, rhs)
+ }
+
+ /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
+ /// the boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120);")]
+ /// assert_eq!(11i8.wrapping_mul(12), -124);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_mul(self, rhs: Self) -> Self {
+ intrinsics::wrapping_mul(self, rhs)
+ }
+
+ /// Wrapping (modular) division. Computes `self / rhs`, wrapping around at the
+ /// boundary of the type.
+ ///
+ /// The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where
+ /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value
+ /// that is too large to represent in the type. In such a case, this function returns `MIN` itself.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);")]
+ /// assert_eq!((-128i8).wrapping_div(-1), -128);
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div(self, rhs: Self) -> Self {
+ self.overflowing_div(rhs).0
+ }
+
+ /// Wrapping Euclidean division. Computes `self.div_euclid(rhs)`,
+ /// wrapping around at the boundary of the type.
+ ///
+ /// Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value
+ /// for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the
+ /// type. In this case, this method returns `MIN` itself.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);")]
+ /// assert_eq!((-128i8).wrapping_div_euclid(-1), -128);
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
+ self.overflowing_div_euclid(rhs).0
+ }
+
+ /// Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the
+ /// boundary of the type.
+ ///
+ /// Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y`
+ /// invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case,
+ /// this function returns `0`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);")]
+ /// assert_eq!((-128i8).wrapping_rem(-1), 0);
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_rem(self, rhs: Self) -> Self {
+ self.overflowing_rem(rhs).0
+ }
+
+ /// Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around
+ /// at the boundary of the type.
+ ///
+ /// Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value
+ /// for the type). In this case, this method returns 0.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);")]
+ /// assert_eq!((-128i8).wrapping_rem_euclid(-1), 0);
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
+ self.overflowing_rem_euclid(rhs).0
+ }
+
+ /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
+ /// of the type.
+ ///
+ /// The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN`
+ /// is the negative minimal value for the type); this is a positive value that is too large to represent
+ /// in the type. In such a case, this function returns `MIN` itself.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), "::MIN);")]
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn wrapping_neg(self) -> Self {
+ self.overflowing_neg().0
+ }
+
+ /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
+ /// any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
+ ///
+ /// Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
+ /// the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
+ /// The primitive integer types all implement a [`rotate_left`](#method.rotate_left) function,
+ /// which may be what you want instead.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128);")]
+ #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);")]
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shl(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+
+ /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`
+ /// removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
+ ///
+ /// Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
+ /// to the range of the type, rather than the bits shifted out of the LHS being returned to the other
+ /// end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
+ /// which may be what you want instead.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1);")]
+ /// assert_eq!((-128i16).wrapping_shr(64), -128);
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shr(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+
+ /// Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at
+ /// the boundary of the type.
+ ///
+ /// The only case where such wrapping can occur is when one takes the absolute value of the negative
+ /// minimal value for the type; this is a positive value that is too large to represent in the type. In
+ /// such a case, this function returns `MIN` itself.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100);")]
+ #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), "::MIN);")]
+ /// assert_eq!((-128i8).wrapping_abs() as u8, 128);
+ /// ```
+ #[stable(feature = "no_panic_abs", since = "1.13.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[allow(unused_attributes)]
+ #[inline]
+ pub const fn wrapping_abs(self) -> Self {
+ if self.is_negative() {
+ self.wrapping_neg()
+ } else {
+ self
+ }
+ }
+
+ /// Computes the absolute value of `self` without any wrapping
+ /// or panicking.
+ ///
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(unsigned_abs)]
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");")]
+ #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");")]
+ /// assert_eq!((-128i8).unsigned_abs(), 128u8);
+ /// ```
+ #[unstable(feature = "unsigned_abs", issue = "74913")]
+ #[inline]
+ pub const fn unsigned_abs(self) -> $UnsignedT {
+ self.wrapping_abs() as $UnsignedT
+ }
+
+ /// Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
+ /// wrapping around at the boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);")]
+ /// assert_eq!(3i8.wrapping_pow(5), -13);
+ /// assert_eq!(3i8.wrapping_pow(6), -39);
+ /// ```
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = acc.wrapping_mul(base);
}
- let mut base = self;
- let mut acc: Self = 1;
- let mut overflown = false;
- // Scratch space for storing results of overflowing_mul.
- let mut r;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- r = acc.overflowing_mul(base);
- acc = r.0;
- overflown |= r.1;
- }
- exp /= 2;
- r = base.overflowing_mul(base);
- base = r.0;
+ exp /= 2;
+ base = base.wrapping_mul(base);
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ acc.wrapping_mul(base)
+ }
+
+ /// Calculates `self` + `rhs`
+ ///
+ /// Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would
+ /// occur. If an overflow would have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), "::MIN, true));")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+
+ /// Calculates `self` - `rhs`
+ ///
+ /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
+ /// would occur. If an overflow would have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+
+ /// Calculates the multiplication of `self` and `rhs`.
+ ///
+ /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
+ /// would occur. If an overflow would have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false));")]
+ /// assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
+
+ /// Calculates the divisor when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
+ /// occur. If an overflow would occur then self is returned.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), "::MIN, true));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (self, true)
+ } else {
+ (self / rhs, false)
+ }
+ }
+
+ /// Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
+ ///
+ /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would
+ /// occur. If an overflow would occur then `self` is returned.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), "::MIN, true));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (self, true)
+ } else {
+ (self.div_euclid(rhs), false)
+ }
+ }
+
+ /// Calculates the remainder when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the remainder after dividing along with a boolean indicating whether an
+ /// arithmetic overflow would occur. If an overflow would occur then 0 is returned.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (0, true)
+ } else {
+ (self % rhs, false)
+ }
+ }
+
+
+ /// Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`.
+ ///
+ /// Returns a tuple of the remainder after dividing along with a boolean indicating whether an
+ /// arithmetic overflow would occur. If an overflow would occur then 0 is returned.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true));")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN && rhs == -1) {
+ (0, true)
+ } else {
+ (self.rem_euclid(rhs), false)
+ }
+ }
+
+
+ /// Negates self, overflowing if this is equal to the minimum value.
+ ///
+ /// Returns a tuple of the negated version of self along with a boolean indicating whether an overflow
+ /// happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the
+ /// minimum value will be returned again and `true` will be returned for an overflow happening.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), "::MIN, true));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[allow(unused_attributes)]
+ pub const fn overflowing_neg(self) -> (Self, bool) {
+ if unlikely!(self == Self::MIN) {
+ (Self::MIN, true)
+ } else {
+ (-self, false)
+ }
+ }
+
+ /// Shifts self left by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
+ /// value was larger than or equal to the number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));")]
+ /// assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+ }
+
+ /// Shifts self right by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean indicating whether the shift
+ /// value was larger than or equal to the number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")]
+ /// assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+ }
+
+ /// Computes the absolute value of `self`.
+ ///
+ /// Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow
+ /// happened. If self is the minimum value
+ #[doc = concat!("(e.g., ", stringify!($SelfT), "::MIN for values of type ", stringify!($SelfT), "),")]
+ /// then the minimum value will be returned again and true will be returned
+ /// for an overflow happening.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false));")]
+ #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false));")]
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), "::MIN, true));")]
+ /// ```
+ #[stable(feature = "no_panic_abs", since = "1.13.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn overflowing_abs(self) -> (Self, bool) {
+ (self.wrapping_abs(), self == Self::MIN)
+ }
+
+ /// Raises self to the power of `exp`, using exponentiation by squaring.
+ ///
+ /// Returns a tuple of the exponentiation along with a bool indicating
+ /// whether an overflow happened.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));")]
+ /// assert_eq!(3i8.overflowing_pow(5), (-13, true));
+ /// ```
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+ if exp == 0 {
+ return (1,false);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+ let mut overflown = false;
+ // Scratch space for storing results of overflowing_mul.
+ let mut r;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ r = acc.overflowing_mul(base);
+ acc = r.0;
overflown |= r.1;
}
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- r = acc.overflowing_mul(base);
- r.1 |= overflown;
- r
- }
- }
-
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type
-
-assert_eq!(x.pow(5), 32);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn pow(self, mut exp: u32) -> Self {
- if exp == 0 {
- return 1;
- }
- let mut base = self;
- let mut acc = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = acc * base;
- }
- exp /= 2;
- base = base * base;
- }
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- acc * base
- }
- }
-
- doc_comment! {
- concat!("Calculates the quotient of Euclidean division of `self` by `rhs`.
-
-This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`,
-with `0 <= self.rem_euclid(rhs) < rhs`.
-
-In other words, the result is `self / rhs` rounded to the integer `n`
-such that `self >= n * rhs`.
-If `self > 0`, this is equal to round towards zero (the default in Rust);
-if `self < 0`, this is equal to round towards +/- infinity.
-
-# Panics
-
-This function will panic if `rhs` is 0 or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-let a: ", stringify!($SelfT), " = 7; // or any other integer type
-let b = 4;
-
-assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1
-assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1
-assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2
-assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn div_euclid(self, rhs: Self) -> Self {
- let q = self / rhs;
- if self % rhs < 0 {
- return if rhs > 0 { q - 1 } else { q + 1 }
- }
- q
- }
- }
-
-
- doc_comment! {
- concat!("Calculates the least nonnegative remainder of `self (mod rhs)`.
-
-This is done as if by the Euclidean division algorithm -- given
-`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and
-`0 <= r < abs(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0 or the division results in overflow.
-
-# Examples
-
-Basic usage:
-
-```
-let a: ", stringify!($SelfT), " = 7; // or any other integer type
-let b = 4;
-
-assert_eq!(a.rem_euclid(b), 3);
-assert_eq!((-a).rem_euclid(b), 1);
-assert_eq!(a.rem_euclid(-b), 3);
-assert_eq!((-a).rem_euclid(-b), 1);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn rem_euclid(self, rhs: Self) -> Self {
- let r = self % rhs;
- if r < 0 {
- if rhs < 0 {
- r - rhs
- } else {
- r + rhs
- }
- } else {
- r
+ exp /= 2;
+ r = base.overflowing_mul(base);
+ base = r.0;
+ overflown |= r.1;
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ r = acc.overflowing_mul(base);
+ r.1 |= overflown;
+ r
+ }
+
+ /// Raises self to the power of `exp`, using exponentiation by squaring.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let x: ", stringify!($SelfT), " = 2; // or any other integer type")]
+ ///
+ /// assert_eq!(x.pow(5), 32);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
+ let mut base = self;
+ let mut acc = 1;
+
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = acc * base;
}
- }
- }
-
- doc_comment! {
- concat!("Computes the absolute value of `self`.
-
-# Overflow behavior
-
-The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an
-`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that
-code in debug mode will trigger a panic on this case and optimized code will return `",
-stringify!($SelfT), "::MIN` without a panic.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10);
-assert_eq!((-10", stringify!($SelfT), ").abs(), 10);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[allow(unused_attributes)]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn abs(self) -> Self {
- // Note that the #[inline] above means that the overflow
- // semantics of the subtraction depend on the crate we're being
- // inlined into.
- if self.is_negative() {
- -self
+ exp /= 2;
+ base = base * base;
+ }
+
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ acc * base
+ }
+
+ /// Calculates the quotient of Euclidean division of `self` by `rhs`.
+ ///
+ /// This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`,
+ /// with `0 <= self.rem_euclid(rhs) < rhs`.
+ ///
+ /// In other words, the result is `self / rhs` rounded to the integer `n`
+ /// such that `self >= n * rhs`.
+ /// If `self > 0`, this is equal to round towards zero (the default in Rust);
+ /// if `self < 0`, this is equal to round towards +/- infinity.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0 or the division results in overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let a: ", stringify!($SelfT), " = 7; // or any other integer type")]
+ /// let b = 4;
+ ///
+ /// assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1
+ /// assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1
+ /// assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2
+ /// assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn div_euclid(self, rhs: Self) -> Self {
+ let q = self / rhs;
+ if self % rhs < 0 {
+ return if rhs > 0 { q - 1 } else { q + 1 }
+ }
+ q
+ }
+
+
+ /// Calculates the least nonnegative remainder of `self (mod rhs)`.
+ ///
+ /// This is done as if by the Euclidean division algorithm -- given
+ /// `r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and
+ /// `0 <= r < abs(rhs)`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0 or the division results in overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let a: ", stringify!($SelfT), " = 7; // or any other integer type")]
+ /// let b = 4;
+ ///
+ /// assert_eq!(a.rem_euclid(b), 3);
+ /// assert_eq!((-a).rem_euclid(b), 1);
+ /// assert_eq!(a.rem_euclid(-b), 3);
+ /// assert_eq!((-a).rem_euclid(-b), 1);
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn rem_euclid(self, rhs: Self) -> Self {
+ let r = self % rhs;
+ if r < 0 {
+ if rhs < 0 {
+ r - rhs
} else {
- self
- }
- }
- }
-
- doc_comment! {
- concat!("Returns a number representing sign of `self`.
-
- - `0` if the number is zero
- - `1` if the number is positive
- - `-1` if the number is negative
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1);
-assert_eq!(0", stringify!($SelfT), ".signum(), 0);
-assert_eq!((-10", stringify!($SelfT), ").signum(), -1);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")]
- #[inline]
- pub const fn signum(self) -> Self {
- match self {
- n if n > 0 => 1,
- 0 => 0,
- _ => -1,
+ r + rhs
}
+ } else {
+ r
}
}
- doc_comment! {
- concat!("Returns `true` if `self` is positive and `false` if the number is zero or
-negative.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!(10", stringify!($SelfT), ".is_positive());
-assert!(!(-10", stringify!($SelfT), ").is_positive());",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn is_positive(self) -> bool { self > 0 }
- }
-
- doc_comment! {
- concat!("Returns `true` if `self` is negative and `false` if the number is zero or
-positive.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative());
-assert!(!10", stringify!($SelfT), ".is_negative());",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
- #[inline]
- pub const fn is_negative(self) -> bool { self < 0 }
- }
-
- doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-big-endian (network) byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
-assert_eq!(bytes, ", $be_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_be().to_ne_bytes()
- }
- }
-
-doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-little-endian byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
-assert_eq!(bytes, ", $le_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_le().to_ne_bytes()
- }
- }
-
- doc_comment! {
- concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-As the target platform's native endianness is used, portable code
-should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
-instead.
-",
-$to_xe_bytes_doc,
-"
-[`to_be_bytes`]: #method.to_be_bytes
-[`to_le_bytes`]: #method.to_le_bytes
-
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(
- bytes,
- if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
- } else {
- ", $le_bytes, "
- }
-);
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute them to arrays of bytes
- #[rustc_allow_const_fn_unstable(const_fn_transmute)]
- #[inline]
- pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { mem::transmute(self) }
- }
- }
-
- doc_comment! {
- concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-[`to_ne_bytes`] should be preferred over this whenever possible.
-
-[`to_ne_bytes`]: #method.to_ne_bytes
-",
-
-"
-# Examples
-
-```
-#![feature(num_as_ne_bytes)]
-let num = ", $swap_op, stringify!($SelfT), ";
-let bytes = num.as_ne_bytes();
-assert_eq!(
- bytes,
- if cfg!(target_endian = \"big\") {
- &", $be_bytes, "
- } else {
- &", $le_bytes, "
- }
-);
-```"),
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { &*(self as *const Self as *const _) }
- }
- }
-
-doc_comment! {
- concat!("Create an integer value from its representation as a byte array in
-big endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_be(Self::from_ne_bytes(bytes))
- }
- }
-
-doc_comment! {
- concat!("
-Create an integer value from its representation as a byte array in
-little endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_le(Self::from_ne_bytes(bytes))
- }
- }
-
- doc_comment! {
- concat!("Create an integer value from its memory representation as a byte
-array in native endianness.
-
-As the target platform's native endianness is used, portable code
-likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
-appropriate instead.
-
-[`from_be_bytes`]: #method.from_be_bytes
-[`from_le_bytes`]: #method.from_le_bytes
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
-} else {
- ", $le_bytes, "
-});
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute to them
- #[rustc_allow_const_fn_unstable(const_fn_transmute)]
- #[inline]
- pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- // SAFETY: integers are plain old datatypes so we can always transmute to them
- unsafe { mem::transmute(bytes) }
- }
- }
-
- doc_comment! {
- concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause a compilation warning,
-new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
-
-Returns the smallest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline(always)]
- #[rustc_promotable]
- #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
- pub const fn min_value() -> Self {
- Self::MIN
- }
- }
-
- doc_comment! {
- concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause a compilation warning,
-new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
-
-Returns the largest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline(always)]
- #[rustc_promotable]
- #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- pub const fn max_value() -> Self {
- Self::MAX
- }
+ /// Computes the absolute value of `self`.
+ ///
+ /// # Overflow behavior
+ ///
+ /// The absolute value of
+ #[doc = concat!("`", stringify!($SelfT), "::MIN`")]
+ /// cannot be represented as an
+ #[doc = concat!("`", stringify!($SelfT), "`,")]
+ /// and attempting to calculate it will cause an overflow. This means
+ /// that code in debug mode will trigger a panic on this case and
+ /// optimized code will return
+ #[doc = concat!("`", stringify!($SelfT), "::MIN`")]
+ /// without a panic.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".abs(), 10);")]
+ #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").abs(), 10);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[allow(unused_attributes)]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn abs(self) -> Self {
+ // Note that the #[inline] above means that the overflow
+ // semantics of the subtraction depend on the crate we're being
+ // inlined into.
+ if self.is_negative() {
+ -self
+ } else {
+ self
+ }
+ }
+
+ /// Returns a number representing sign of `self`.
+ ///
+ /// - `0` if the number is zero
+ /// - `1` if the number is positive
+ /// - `-1` if the number is negative
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".signum(), 1);")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".signum(), 0);")]
+ #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").signum(), -1);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")]
+ #[inline]
+ pub const fn signum(self) -> Self {
+ match self {
+ n if n > 0 => 1,
+ 0 => 0,
+ _ => -1,
+ }
+ }
+
+ /// Returns `true` if `self` is positive and `false` if the number is zero or
+ /// negative.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert!(10", stringify!($SelfT), ".is_positive());")]
+ #[doc = concat!("assert!(!(-10", stringify!($SelfT), ").is_positive());")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn is_positive(self) -> bool { self > 0 }
+
+ /// Returns `true` if `self` is negative and `false` if the number is zero or
+ /// positive.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert!((-10", stringify!($SelfT), ").is_negative());")]
+ #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_negative());")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+ #[inline]
+ pub const fn is_negative(self) -> bool { self < 0 }
+
+ /// Return the memory representation of this integer as a byte array in
+ /// big-endian (network) byte order.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();")]
+ #[doc = concat!("assert_eq!(bytes, ", $be_bytes, ");")]
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_be().to_ne_bytes()
+ }
+
+ /// Return the memory representation of this integer as a byte array in
+ /// little-endian byte order.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();")]
+ #[doc = concat!("assert_eq!(bytes, ", $le_bytes, ");")]
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_le().to_ne_bytes()
+ }
+
+ /// Return the memory representation of this integer as a byte array in
+ /// native byte order.
+ ///
+ /// As the target platform's native endianness is used, portable code
+ /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
+ /// instead.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// [`to_be_bytes`]: #method.to_be_bytes
+ /// [`to_le_bytes`]: #method.to_le_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();")]
+ /// assert_eq!(
+ /// bytes,
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" ", $be_bytes)]
+ /// } else {
+ #[doc = concat!(" ", $le_bytes)]
+ /// }
+ /// );
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute them to arrays of bytes
+ #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ // SAFETY: integers are plain old datatypes so we can always transmute them to
+ // arrays of bytes
+ unsafe { mem::transmute(self) }
+ }
+
+ /// Return the memory representation of this integer as a byte array in
+ /// native byte order.
+ ///
+ /// [`to_ne_bytes`] should be preferred over this whenever possible.
+ ///
+ /// [`to_ne_bytes`]: #method.to_ne_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_as_ne_bytes)]
+ #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
+ /// let bytes = num.as_ne_bytes();
+ /// assert_eq!(
+ /// bytes,
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" &", $be_bytes)]
+ /// } else {
+ #[doc = concat!(" &", $le_bytes)]
+ /// }
+ /// );
+ /// ```
+ #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+ #[inline]
+ pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
+ // SAFETY: integers are plain old datatypes so we can always transmute them to
+ // arrays of bytes
+ unsafe { &*(self as *const Self as *const _) }
+ }
+
+ /// Create an integer value from its representation as a byte array in
+ /// big endian.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");")]
+ #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+ /// ```
+ ///
+ /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ ///
+ #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+ #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+ /// *input = rest;
+ #[doc = concat!(" ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")]
+ /// }
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_be(Self::from_ne_bytes(bytes))
+ }
+
+ /// Create an integer value from its representation as a byte array in
+ /// little endian.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");")]
+ #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+ /// ```
+ ///
+ /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ ///
+ #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+ #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+ /// *input = rest;
+ #[doc = concat!(" ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")]
+ /// }
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_le(Self::from_ne_bytes(bytes))
+ }
+
+ /// Create an integer value from its memory representation as a byte
+ /// array in native endianness.
+ ///
+ /// As the target platform's native endianness is used, portable code
+ /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
+ /// appropriate instead.
+ ///
+ /// [`from_be_bytes`]: #method.from_be_bytes
+ /// [`from_le_bytes`]: #method.from_le_bytes
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {")]
+ #[doc = concat!(" ", $be_bytes)]
+ /// } else {
+ #[doc = concat!(" ", $le_bytes)]
+ /// });
+ #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+ /// ```
+ ///
+ /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ ///
+ #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+ #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+ /// *input = rest;
+ #[doc = concat!(" ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")]
+ /// }
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute to them
+ #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ // SAFETY: integers are plain old datatypes so we can always transmute to them
+ unsafe { mem::transmute(bytes) }
+ }
+
+ /// **This method is soft-deprecated.**
+ ///
+ /// Although using it won’t cause a compilation warning, new code should use
+ #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")]
+ /// instead.
+ ///
+ /// Returns the smallest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline(always)]
+ #[rustc_promotable]
+ #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
+ pub const fn min_value() -> Self {
+ Self::MIN
+ }
+
+ /// **This method is soft-deprecated.**
+ ///
+ /// Although using it won’t cause a compilation warning, new code should use
+ #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")]
+ /// instead.
+ ///
+ /// Returns the largest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline(always)]
+ #[rustc_promotable]
+ #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+ pub const fn max_value() -> Self {
+ Self::MAX
}
}
}
};
}
-macro_rules! doc_comment {
- ($x:expr, $($tt:tt)*) => {
- #[doc = $x]
- $($tt)*
- };
-}
-
// All these modules are technically private and only exposed for coretests:
pub mod bignum;
pub mod dec2flt;
#[lang = "i8"]
impl i8 {
- int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
+ int_impl! { i8, i8, u8, 8, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
"[0x12]", "[0x12]", "", "" }
}
#[lang = "i16"]
impl i16 {
- int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
+ int_impl! { i16, i16, u16, 16, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
"0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
}
#[lang = "i32"]
impl i32 {
- int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
+ int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78]", "", "" }
}
#[lang = "i64"]
impl i64 {
- int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12,
+ int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, 12,
"0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
"0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
#[lang = "i128"]
impl i128 {
int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728,
- 170141183460469231731687303715884105727, "", "", 16,
+ 170141183460469231731687303715884105727, 16,
"0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
"0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
"[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
#[cfg(target_pointer_width = "16")]
#[lang = "isize"]
impl isize {
- int_impl! { isize, i16, usize, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234",
+ int_impl! { isize, i16, usize, 16, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
"0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[cfg(target_pointer_width = "32")]
#[lang = "isize"]
impl isize {
- int_impl! { isize, i32, usize, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
+ int_impl! { isize, i32, usize, 32, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
#[cfg(target_pointer_width = "64")]
#[lang = "isize"]
impl isize {
- int_impl! { isize, i64, usize, 64, -9223372036854775808, 9223372036854775807, "", "",
+ int_impl! { isize, i64, usize, 64, -9223372036854775808, 9223372036854775807,
12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
"0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
#[lang = "u8"]
impl u8 {
- uint_impl! { u8, u8, 8, 255, "", "", 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
+ uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
"[0x12]", "", "" }
/// Checks if the value is within the ASCII range.
#[lang = "u16"]
impl u16 {
- uint_impl! { u16, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+ uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
}
#[lang = "u32"]
impl u32 {
- uint_impl! { u32, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678",
+ uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
}
#[lang = "u64"]
impl u64 {
- uint_impl! { u64, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa",
+ uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
#[lang = "u128"]
impl u128 {
- uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "", "", 16,
+ uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16,
"0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
"0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
"[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
#[cfg(target_pointer_width = "16")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+ uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[cfg(target_pointer_width = "32")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678",
+ uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[cfg(target_pointer_width = "64")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa",
+ uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
//! Definitions of integer that is known not to equal zero.
use crate::fmt;
-use crate::ops::{BitOr, BitOrAssign};
+use crate::ops::{BitOr, BitOrAssign, Div, Rem};
use crate::str::FromStr;
use super::from_str_radix;
use super::{IntErrorKind, ParseIntError};
use crate::intrinsics;
-macro_rules! doc_comment {
- ($x:expr, $($tt:tt)*) => {
- #[doc = $x]
- $($tt)*
- };
-}
-
macro_rules! impl_nonzero_fmt {
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
$(
macro_rules! nonzero_integers {
( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
$(
- doc_comment! {
- concat!("An integer that is known not to equal zero.
-
-This enables some memory layout optimization.
-For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:
-
-```rust
-use std::mem::size_of;
-assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
-">());
-```"),
- #[$stability]
- #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
- #[repr(transparent)]
- #[rustc_layout_scalar_valid_range_start(1)]
- #[rustc_nonnull_optimization_guaranteed]
- pub struct $Ty($Int);
- }
+ /// An integer that is known not to equal zero.
+ ///
+ /// This enables some memory layout optimization.
+ #[doc = concat!("For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:")]
+ ///
+ /// ```rust
+ /// use std::mem::size_of;
+ #[doc = concat!("assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int), ">());")]
+ /// ```
+ #[$stability]
+ #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ #[repr(transparent)]
+ #[rustc_layout_scalar_valid_range_start(1)]
+ #[rustc_nonnull_optimization_guaranteed]
+ pub struct $Ty($Int);
impl $Ty {
/// Creates a non-zero without checking the value.
#[stable(feature = "from_nonzero", since = "1.31.0")]
impl From<$Ty> for $Int {
- doc_comment! {
- concat!(
-"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
- #[inline]
- fn from(nonzero: $Ty) -> Self {
- nonzero.0
- }
+ #[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")]
+ #[inline]
+ fn from(nonzero: $Ty) -> Self {
+ nonzero.0
}
}
( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => {
$(
impl $Ty {
- doc_comment! {
- concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(nonzero_leading_trailing_zeros)]
-let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();
-
-assert_eq!(n.leading_zeros(), 0);
-```"),
- #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
- #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
- #[inline]
- pub const fn leading_zeros(self) -> u32 {
- // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
- unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
- }
+ /// Returns the number of leading zeros in the binary representation of `self`.
+ ///
+ /// On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_leading_trailing_zeros)]
+ #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();")]
+ ///
+ /// assert_eq!(n.leading_zeros(), 0);
+ /// ```
+ #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+ #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+ #[inline]
+ pub const fn leading_zeros(self) -> u32 {
+ // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
+ unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
}
- doc_comment! {
- concat!("Returns the number of trailing zeros in the binary representation
-of `self`.
-
-On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(nonzero_leading_trailing_zeros)]
-let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();
-
-assert_eq!(n.trailing_zeros(), 3);
-```"),
- #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
- #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
- #[inline]
- pub const fn trailing_zeros(self) -> u32 {
- // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
- unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
- }
+ /// Returns the number of trailing zeros in the binary representation
+ /// of `self`.
+ ///
+ /// On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_leading_trailing_zeros)]
+ #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();")]
+ ///
+ /// assert_eq!(n.trailing_zeros(), 3);
+ /// ```
+ #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+ #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
+ #[inline]
+ pub const fn trailing_zeros(self) -> u32 {
+ // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
+ unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
}
}
NonZeroI128(u128), -1i128;
NonZeroIsize(usize), -1isize;
}
+
+macro_rules! nonzero_integers_div {
+ ( $( $Ty: ident($Int: ty); )+ ) => {
+ $(
+ #[stable(feature = "nonzero_div", since = "1.51.0")]
+ impl Div<$Ty> for $Int {
+ type Output = $Int;
+ /// This operation rounds towards zero,
+ /// truncating any fractional part of the exact result, and cannot panic.
+ #[inline]
+ fn div(self, other: $Ty) -> $Int {
+ // SAFETY: div by zero is checked because `other` is a nonzero,
+ // and MIN/-1 is checked because `self` is an unsigned int.
+ unsafe { crate::intrinsics::unchecked_div(self, other.get()) }
+ }
+ }
+
+ #[stable(feature = "nonzero_div", since = "1.51.0")]
+ impl Rem<$Ty> for $Int {
+ type Output = $Int;
+ /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
+ #[inline]
+ fn rem(self, other: $Ty) -> $Int {
+ // SAFETY: rem by zero is checked because `other` is a nonzero,
+ // and MIN/-1 is checked because `self` is an unsigned int.
+ unsafe { crate::intrinsics::unchecked_rem(self, other.get()) }
+ }
+ }
+ )+
+ }
+}
+
+nonzero_integers_div! {
+ NonZeroU8(u8);
+ NonZeroU16(u16);
+ NonZeroU32(u32);
+ NonZeroU64(u64);
+ NonZeroU128(u128);
+ NonZeroUsize(usize);
+}
#![doc(hidden)]
-macro_rules! doc_comment {
- ($x:expr, $($tt:tt)*) => {
- #[doc = $x]
- $($tt)*
- };
-}
-
macro_rules! int_module {
($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
($T:ident, #[$attr:meta]) => (
- doc_comment! {
- concat!("The smallest value that can be represented by this integer type.
-Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead.
-
-# Examples
-
-```rust
-// deprecated way
-let min = std::", stringify!($T), "::MIN;
-
-// intended way
-let min = ", stringify!($T), "::MIN;
-```
-"),
- #[$attr]
- pub const MIN: $T = $T::MIN;
- }
-
- doc_comment! {
- concat!("The largest value that can be represented by this integer type.
-Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead.
-
-# Examples
-
-```rust
-// deprecated way
-let max = std::", stringify!($T), "::MAX;
-
-// intended way
-let max = ", stringify!($T), "::MAX;
-```
-"),
- #[$attr]
- pub const MAX: $T = $T::MAX;
- }
+ #[doc = concat!(
+ "The smallest value that can be represented by this integer type. Use ",
+ "[`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN)",
+ " instead.",
+ )]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// // deprecated way
+ #[doc = concat!("let min = std::", stringify!($T), "::MIN;")]
+ ///
+ /// // intended way
+ #[doc = concat!("let min = ", stringify!($T), "::MIN;")]
+ /// ```
+ ///
+ #[$attr]
+ pub const MIN: $T = $T::MIN;
+
+ #[doc = concat!(
+ "The largest value that can be represented by this integer type. Use ",
+ "[`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX)",
+ " instead.",
+ )]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// // deprecated way
+ #[doc = concat!("let max = std::", stringify!($T), "::MAX;")]
+ ///
+ /// // intended way
+ #[doc = concat!("let max = ", stringify!($T), "::MAX;")]
+ /// ```
+ ///
+ #[$attr]
+ pub const MAX: $T = $T::MAX;
)
}
macro_rules! uint_impl {
- ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr,
+ ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr,
$rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
- doc_comment! {
- concat!("The smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MIN: Self = 0;
- }
-
- doc_comment! {
- concat!("The largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");",
-$EndFeature, "
-```"),
- #[stable(feature = "assoc_int_consts", since = "1.43.0")]
- pub const MAX: Self = !0;
- }
-
- doc_comment! {
- concat!("The size of this integer type in bits.
-
-# Examples
-
-```
-", $Feature, "#![feature(int_bits_const)]
-assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");",
-$EndFeature, "
-```"),
- #[unstable(feature = "int_bits_const", issue = "76904")]
- pub const BITS: u32 = $BITS;
- }
-
- doc_comment! {
- concat!("Converts a string slice in a given base to an integer.
-
-The string is expected to be an optional `+` sign
-followed by digits.
-Leading and trailing whitespace represent an error.
-Digits are a subset of these characters, depending on `radix`:
-
-* `0-9`
-* `a-z`
-* `A-Z`
-
-# Panics
-
-This function panics if `radix` is not in the range from 2 to 36.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
- from_str_radix(src, radix)
- }
- }
-
- doc_comment! {
- concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
+ /// The smallest value that can be represented by this integer type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN, 0);")]
+ /// ```
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MIN: Self = 0;
-Basic usage:
+ /// The largest value that can be represented by this integer type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");")]
+ /// ```
+ #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+ pub const MAX: Self = !0;
-```
-", $Feature, "let n = 0b01001100", stringify!($SelfT), ";
+ /// The size of this integer type in bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(int_bits_const)]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
+ /// ```
+ #[unstable(feature = "int_bits_const", issue = "76904")]
+ pub const BITS: u32 = $BITS;
-assert_eq!(n.count_ones(), 3);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[doc(alias = "popcount")]
- #[doc(alias = "popcnt")]
- #[inline]
- pub const fn count_ones(self) -> u32 {
- intrinsics::ctpop(self as $ActualT) as u32
- }
+ /// Converts a string slice in a given base to an integer.
+ ///
+ /// The string is expected to be an optional `+` sign
+ /// followed by digits.
+ /// Leading and trailing whitespace represent an error.
+ /// Digits are a subset of these characters, depending on `radix`:
+ ///
+ /// * `0-9`
+ /// * `a-z`
+ /// * `A-Z`
+ ///
+ /// # Panics
+ ///
+ /// This function panics if `radix` is not in the range from 2 to 36.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ from_str_radix(src, radix)
}
- doc_comment! {
- concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn count_zeros(self) -> u32 {
- (!self).count_ones()
- }
+ /// Returns the number of ones in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0b01001100", stringify!($SelfT), ";")]
+ ///
+ /// assert_eq!(n.count_ones(), 3);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[doc(alias = "popcount")]
+ #[doc(alias = "popcnt")]
+ #[inline]
+ pub const fn count_ones(self) -> u32 {
+ intrinsics::ctpop(self as $ActualT) as u32
}
- doc_comment! {
- concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2;
-
-assert_eq!(n.leading_zeros(), 2);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn leading_zeros(self) -> u32 {
- intrinsics::ctlz(self as $ActualT) as u32
- }
+ /// Returns the number of zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn count_zeros(self) -> u32 {
+ (!self).count_ones()
}
- doc_comment! {
- concat!("Returns the number of trailing zeros in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b0101000", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn trailing_zeros(self) -> u32 {
- intrinsics::cttz(self) as u32
- }
+ /// Returns the number of leading zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", stringify!($SelfT), "::MAX >> 2;")]
+ ///
+ /// assert_eq!(n.leading_zeros(), 2);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn leading_zeros(self) -> u32 {
+ intrinsics::ctlz(self as $ActualT) as u32
}
- doc_comment! {
- concat!("Returns the number of leading ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2);
-
-assert_eq!(n.leading_ones(), 2);", $EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn leading_ones(self) -> u32 {
- (!self).leading_zeros()
- }
+ /// Returns the number of trailing zeros in the binary representation
+ /// of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0b0101000", stringify!($SelfT), ";")]
+ ///
+ /// assert_eq!(n.trailing_zeros(), 3);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn trailing_zeros(self) -> u32 {
+ intrinsics::cttz(self) as u32
}
- doc_comment! {
- concat!("Returns the number of trailing ones in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0b1010111", stringify!($SelfT), ";
-
-assert_eq!(n.trailing_ones(), 3);", $EndFeature, "
-```"),
- #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
- #[inline]
- pub const fn trailing_ones(self) -> u32 {
- (!self).trailing_zeros()
- }
+ /// Returns the number of leading ones in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = !(", stringify!($SelfT), "::MAX >> 2);")]
+ ///
+ /// assert_eq!(n.leading_ones(), 2);
+ /// ```
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn leading_ones(self) -> u32 {
+ (!self).leading_zeros()
}
- doc_comment! {
- concat!("Shifts the bits to the left by a specified amount, `n`,
-wrapping the truncated bits to the end of the resulting integer.
-
-Please note this isn't the same operation as the `<<` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_op, stringify!($SelfT), ";
-let m = ", $rot_result, ";
-
-assert_eq!(n.rotate_left(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_left(self, n: u32) -> Self {
- intrinsics::rotate_left(self, n as $SelfT)
- }
+ /// Returns the number of trailing ones in the binary representation
+ /// of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0b1010111", stringify!($SelfT), ";")]
+ ///
+ /// assert_eq!(n.trailing_ones(), 3);
+ /// ```
+ #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
+ #[inline]
+ pub const fn trailing_ones(self) -> u32 {
+ (!self).trailing_zeros()
}
- doc_comment! {
- concat!("Shifts the bits to the right by a specified amount, `n`,
-wrapping the truncated bits to the beginning of the resulting
-integer.
-
-Please note this isn't the same operation as the `>>` shifting operator!
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $rot_result, stringify!($SelfT), ";
-let m = ", $rot_op, ";
-
-assert_eq!(n.rotate_right(", $rot, "), m);
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn rotate_right(self, n: u32) -> Self {
- intrinsics::rotate_right(self, n as $SelfT)
- }
+ /// Shifts the bits to the left by a specified amount, `n`,
+ /// wrapping the truncated bits to the end of the resulting integer.
+ ///
+ /// Please note this isn't the same operation as the `<<` shifting operator!
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $rot_op, stringify!($SelfT), ";")]
+ #[doc = concat!("let m = ", $rot_result, ";")]
+ ///
+ #[doc = concat!("assert_eq!(n.rotate_left(", $rot, "), m);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_left(self, n: u32) -> Self {
+ intrinsics::rotate_left(self, n as $SelfT)
}
- doc_comment! {
- concat!("
-Reverses the byte order of the integer.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.swap_bytes();
-
-assert_eq!(m, ", $swapped, ");
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn swap_bytes(self) -> Self {
- intrinsics::bswap(self as $ActualT) as Self
- }
+ /// Shifts the bits to the right by a specified amount, `n`,
+ /// wrapping the truncated bits to the beginning of the resulting
+ /// integer.
+ ///
+ /// Please note this isn't the same operation as the `>>` shifting operator!
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $rot_result, stringify!($SelfT), ";")]
+ #[doc = concat!("let m = ", $rot_op, ";")]
+ ///
+ #[doc = concat!("assert_eq!(n.rotate_right(", $rot, "), m);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn rotate_right(self, n: u32) -> Self {
+ intrinsics::rotate_right(self, n as $SelfT)
}
- doc_comment! {
- concat!("Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
- second least-significant bit becomes second most-significant bit, etc.
-
-# Examples
-
-Basic usage:
-
-```
-let n = ", $swap_op, stringify!($SelfT), ";
-let m = n.reverse_bits();
-
-assert_eq!(m, ", $reversed, ");
-assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());
-```"),
- #[stable(feature = "reverse_bits", since = "1.37.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- #[must_use]
- pub const fn reverse_bits(self) -> Self {
- intrinsics::bitreverse(self as $ActualT) as Self
- }
+ /// Reverses the byte order of the integer.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+ /// let m = n.swap_bytes();
+ ///
+ #[doc = concat!("assert_eq!(m, ", $swapped, ");")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn swap_bytes(self) -> Self {
+ intrinsics::bswap(self as $ActualT) as Self
}
- doc_comment! {
- concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn from_be(x: Self) -> Self {
- #[cfg(target_endian = "big")]
- {
- x
- }
- #[cfg(not(target_endian = "big"))]
- {
- x.swap_bytes()
- }
- }
+ /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
+ /// second least-significant bit becomes second most-significant bit, etc.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")]
+ /// let m = n.reverse_bits();
+ ///
+ #[doc = concat!("assert_eq!(m, ", $reversed, ");")]
+ #[doc = concat!("assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());")]
+ /// ```
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ #[must_use]
+ pub const fn reverse_bits(self) -> Self {
+ intrinsics::bitreverse(self as $ActualT) as Self
}
- doc_comment! {
- concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n)
-} else {
- assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn from_le(x: Self) -> Self {
- #[cfg(target_endian = "little")]
- {
- x
- }
- #[cfg(not(target_endian = "little"))]
- {
- x.swap_bytes()
- }
+ /// Converts an integer from big endian to the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_be(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes())")]
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn from_be(x: Self) -> Self {
+ #[cfg(target_endian = "big")]
+ {
+ x
}
- }
-
- doc_comment! {
- concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(n.to_be(), n)
-} else {
- assert_eq!(n.to_be(), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn to_be(self) -> Self { // or not to be?
- #[cfg(target_endian = "big")]
- {
- self
- }
- #[cfg(not(target_endian = "big"))]
- {
- self.swap_bytes()
- }
+ #[cfg(not(target_endian = "big"))]
+ {
+ x.swap_bytes()
}
}
- doc_comment! {
- concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "let n = 0x1A", stringify!($SelfT), ";
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(n.to_le(), n)
-} else {
- assert_eq!(n.to_le(), n.swap_bytes())
-}", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
- #[inline]
- pub const fn to_le(self) -> Self {
- #[cfg(target_endian = "little")]
- {
- self
- }
- #[cfg(not(target_endian = "little"))]
- {
- self.swap_bytes()
- }
+ /// Converts an integer from little endian to the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_le(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes())")]
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn from_le(x: Self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ x
}
- }
-
- doc_comment! {
- concat!("Checked integer addition. Computes `self + rhs`, returning `None`
-if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ",
-"Some(", stringify!($SelfT), "::MAX - 1));
-assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_add(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_add(rhs);
- if unlikely!(b) {None} else {Some(a)}
+ #[cfg(not(target_endian = "little"))]
+ {
+ x.swap_bytes()
}
}
- doc_comment! {
- concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
-"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_add`.
- unsafe { intrinsics::unchecked_add(self, rhs) }
+ /// Converts `self` to big endian from the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ /// assert_eq!(n.to_be(), n)
+ /// } else {
+ /// assert_eq!(n.to_be(), n.swap_bytes())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn to_be(self) -> Self { // or not to be?
+ #[cfg(target_endian = "big")]
+ {
+ self
}
- }
-
- doc_comment! {
- concat!("Checked integer subtraction. Computes `self - rhs`, returning
-`None` if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0));
-assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_sub(rhs);
- if unlikely!(b) {None} else {Some(a)}
+ #[cfg(not(target_endian = "big"))]
+ {
+ self.swap_bytes()
}
}
- doc_comment! {
- concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
-"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_sub`.
- unsafe { intrinsics::unchecked_sub(self, rhs) }
+ /// Converts `self` to little endian from the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ /// assert_eq!(n.to_le(), n)
+ /// } else {
+ /// assert_eq!(n.to_le(), n.swap_bytes())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
+ #[inline]
+ pub const fn to_le(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
}
- }
-
- doc_comment! {
- concat!("Checked integer multiplication. Computes `self * rhs`, returning
-`None` if overflow occurred.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
- let (a, b) = self.overflowing_mul(rhs);
- if unlikely!(b) {None} else {Some(a)}
+ #[cfg(not(target_endian = "little"))]
+ {
+ self.swap_bytes()
}
}
- doc_comment! {
- concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
-"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."),
- #[unstable(
- feature = "unchecked_math",
- reason = "niche optimization path",
- issue = "none",
- )]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
- // SAFETY: the caller must uphold the safety contract for
- // `unchecked_mul`.
- unsafe { intrinsics::unchecked_mul(self, rhs) }
- }
+ /// Checked integer addition. Computes `self + rhs`, returning `None`
+ /// if overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!(
+ "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ",
+ "Some(", stringify!($SelfT), "::MAX - 1));"
+ )]
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_add(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
+ /// cannot occur. This results in undefined behavior when
+ #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_add`.
+ unsafe { intrinsics::unchecked_add(self, rhs) }
}
- doc_comment! {
- concat!("Checked integer division. Computes `self / rhs`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));
-assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- // SAFETY: div by zero has been checked above and unsigned types have no other
- // failure modes for division
- Some(unsafe { intrinsics::unchecked_div(self, rhs) })
- }
- }
+ /// Checked integer subtraction. Computes `self - rhs`, returning
+ /// `None` if overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0));")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_sub(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
+ /// cannot occur. This results in undefined behavior when
+ #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_sub`.
+ unsafe { intrinsics::unchecked_sub(self, rhs) }
}
- doc_comment! {
- concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64));
-assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- Some(self.div_euclid(rhs))
- }
- }
+ /// Checked integer multiplication. Computes `self * rhs`, returning
+ /// `None` if overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_mul(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
+
+ /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
+ /// cannot occur. This results in undefined behavior when
+ #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "none",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_mul`.
+ unsafe { intrinsics::unchecked_mul(self, rhs) }
}
-
- doc_comment! {
- concat!("Checked integer remainder. Computes `self % rhs`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- // SAFETY: div by zero has been checked above and unsigned types have no other
- // failure modes for division
- Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
- }
+ /// Checked integer division. Computes `self / rhs`, returning `None`
+ /// if `rhs == 0`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));")]
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ // SAFETY: div by zero has been checked above and unsigned types have no other
+ // failure modes for division
+ Some(unsafe { intrinsics::unchecked_div(self, rhs) })
}
}
- doc_comment! {
- concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None`
-if `rhs == 0`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));
-assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
- None
- } else {
- Some(self.rem_euclid(rhs))
- }
+ /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None`
+ /// if `rhs == 0`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64));")]
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None);")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ Some(self.div_euclid(rhs))
}
}
- doc_comment! {
- concat!("Checked negation. Computes `-self`, returning `None` unless `self ==
-0`.
-
-Note that negating any positive integer will overflow.
-
-# Examples
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0));
-assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn checked_neg(self) -> Option<Self> {
- let (a, b) = self.overflowing_neg();
- if unlikely!(b) {None} else {Some(a)}
+ /// Checked integer remainder. Computes `self % rhs`, returning `None`
+ /// if `rhs == 0`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ // SAFETY: div by zero has been checked above and unsigned types have no other
+ // failure modes for division
+ Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
}
}
- doc_comment! {
- concat!("Checked shift left. Computes `self << rhs`, returning `None`
-if `rhs` is larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shl(rhs);
- if unlikely!(b) {None} else {Some(a)}
+ /// Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None`
+ /// if `rhs == 0`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
+ if unlikely!(rhs == 0) {
+ None
+ } else {
+ Some(self.rem_euclid(rhs))
}
}
- doc_comment! {
- concat!("Checked shift right. Computes `self >> rhs`, returning `None`
-if `rhs` is larger than or equal to the number of bits in `self`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));
-assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
- let (a, b) = self.overflowing_shr(rhs);
- if unlikely!(b) {None} else {Some(a)}
- }
+ /// Checked negation. Computes `-self`, returning `None` unless `self ==
+ /// 0`.
+ ///
+ /// Note that negating any positive integer will overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0));")]
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn checked_neg(self) -> Option<Self> {
+ let (a, b) = self.overflowing_neg();
+ if unlikely!(b) {None} else {Some(a)}
}
- doc_comment! {
- concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
-overflow occurred.
+ /// Checked shift left. Computes `self << rhs`, returning `None`
+ /// if `rhs` is larger than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")]
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shl(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
-# Examples
+ /// Checked shift right. Computes `self >> rhs`, returning `None`
+ /// if `rhs` is larger than or equal to the number of bits in `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));")]
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
+ let (a, b) = self.overflowing_shr(rhs);
+ if unlikely!(b) {None} else {Some(a)}
+ }
-Basic usage:
+ /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
+ /// overflow occurred.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);")]
+ /// ```
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+ if exp == 0 {
+ return Some(1);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
- if exp == 0 {
- return Some(1);
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = try_opt!(acc.checked_mul(base));
- }
- exp /= 2;
- base = try_opt!(base.checked_mul(base));
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = try_opt!(acc.checked_mul(base));
}
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
-
- Some(try_opt!(acc.checked_mul(base)))
+ exp /= 2;
+ base = try_opt!(base.checked_mul(base));
}
- }
-
- doc_comment! {
- concat!("Saturating integer addition. Computes `self + rhs`, saturating at
-the numeric bounds instead of overflowing.
-
-# Examples
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_add(self, rhs: Self) -> Self {
- intrinsics::saturating_add(self, rhs)
- }
+ Some(try_opt!(acc.checked_mul(base)))
}
- doc_comment! {
- concat!("Saturating integer subtraction. Computes `self - rhs`, saturating
-at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);
-assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[inline]
- pub const fn saturating_sub(self, rhs: Self) -> Self {
- intrinsics::saturating_sub(self, rhs)
- }
+ /// Saturating integer addition. Computes `self + rhs`, saturating at
+ /// the numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_add(self, rhs: Self) -> Self {
+ intrinsics::saturating_add(self, rhs)
}
- doc_comment! {
- concat!("Saturating integer multiplication. Computes `self * rhs`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20);
-assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT),
-"::MAX);", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_mul(self, rhs: Self) -> Self {
- match self.checked_mul(rhs) {
- Some(x) => x,
- None => Self::MAX,
- }
- }
+ /// Saturating integer subtraction. Computes `self - rhs`, saturating
+ /// at the numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);")]
+ #[doc = concat!("assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[inline]
+ pub const fn saturating_sub(self, rhs: Self) -> Self {
+ intrinsics::saturating_sub(self, rhs)
}
- doc_comment! {
- concat!("Saturating integer exponentiation. Computes `self.pow(exp)`,
-saturating at the numeric bounds instead of overflowing.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "
-assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);
-assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);",
-$EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn saturating_pow(self, exp: u32) -> Self {
- match self.checked_pow(exp) {
- Some(x) => x,
- None => Self::MAX,
- }
+ /// Saturating integer multiplication. Computes `self * rhs`,
+ /// saturating at the numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20);")]
+ #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT),"::MAX);")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_mul(self, rhs: Self) -> Self {
+ match self.checked_mul(rhs) {
+ Some(x) => x,
+ None => Self::MAX,
}
}
- doc_comment! {
- concat!("Wrapping (modular) addition. Computes `self + rhs`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255);
-assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_add(self, rhs: Self) -> Self {
- intrinsics::wrapping_add(self, rhs)
+ /// Saturating integer exponentiation. Computes `self.pow(exp)`,
+ /// saturating at the numeric bounds instead of overflowing.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);")]
+ /// ```
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn saturating_pow(self, exp: u32) -> Self {
+ match self.checked_pow(exp) {
+ Some(x) => x,
+ None => Self::MAX,
}
}
- doc_comment! {
- concat!("Wrapping (modular) subtraction. Computes `self - rhs`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
+ /// Wrapping (modular) addition. Computes `self + rhs`,
+ /// wrapping around at the boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255);")]
+ #[doc = concat!("assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_add(self, rhs: Self) -> Self {
+ intrinsics::wrapping_add(self, rhs)
+ }
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0);
-assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);",
-$EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_sub(self, rhs: Self) -> Self {
- intrinsics::wrapping_sub(self, rhs)
- }
+ /// Wrapping (modular) subtraction. Computes `self - rhs`,
+ /// wrapping around at the boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0);")]
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_sub(self, rhs: Self) -> Self {
+ intrinsics::wrapping_sub(self, rhs)
}
/// Wrapping (modular) multiplication. Computes `self *
/// Which explains why `u8` is used here.
///
/// ```
- /// assert_eq!(10u8.wrapping_mul(12), 120);
- /// assert_eq!(25u8.wrapping_mul(12), 44);
+ /// assert_eq!(10u8.wrapping_mul(12), 120);
+ /// assert_eq!(25u8.wrapping_mul(12), 44);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_mul(self, rhs: Self) -> Self {
+ intrinsics::wrapping_mul(self, rhs)
+ }
+
+ /// Wrapping (modular) division. Computes `self / rhs`.
+ /// Wrapped division on unsigned types is just normal division.
+ /// There's no way wrapping could ever happen.
+ /// This function exists, so that all operations
+ /// are accounted for in the wrapping operations.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);")]
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div(self, rhs: Self) -> Self {
+ self / rhs
+ }
+
+ /// Wrapping Euclidean division. Computes `self.div_euclid(rhs)`.
+ /// Wrapped division on unsigned types is just normal division.
+ /// There's no way wrapping could ever happen.
+ /// This function exists, so that all operations
+ /// are accounted for in the wrapping operations.
+ /// Since, for the positive integers, all common
+ /// definitions of division are equal, this
+ /// is exactly equal to `self.wrapping_div(rhs)`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
+ self / rhs
+ }
+
+ /// Wrapping (modular) remainder. Computes `self % rhs`.
+ /// Wrapped remainder calculation on unsigned types is
+ /// just the regular remainder calculation.
+ /// There's no way wrapping could ever happen.
+ /// This function exists, so that all operations
+ /// are accounted for in the wrapping operations.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);")]
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_rem(self, rhs: Self) -> Self {
+ self % rhs
+ }
+
+ /// Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`.
+ /// Wrapped modulo calculation on unsigned types is
+ /// just the regular remainder calculation.
+ /// There's no way wrapping could ever happen.
+ /// This function exists, so that all operations
+ /// are accounted for in the wrapping operations.
+ /// Since, for the positive integers, all common
+ /// definitions of division are equal, this
+ /// is exactly equal to `self.wrapping_rem(rhs)`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);")]
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
#[must_use = "this returns the result of the operation, \
- without modifying the original"]
+ without modifying the original"]
#[inline]
- pub const fn wrapping_mul(self, rhs: Self) -> Self {
- intrinsics::wrapping_mul(self, rhs)
- }
-
- doc_comment! {
- concat!("Wrapping (modular) division. Computes `self / rhs`.
-Wrapped division on unsigned types is just normal division.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div(self, rhs: Self) -> Self {
- self / rhs
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`.
-Wrapped division on unsigned types is just normal division.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.wrapping_div(rhs)`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_div_euclid(self, rhs: Self) -> Self {
- self / rhs
- }
- }
-
- doc_comment! {
- concat!("Wrapping (modular) remainder. Computes `self % rhs`.
-Wrapped remainder calculation on unsigned types is
-just the regular remainder calculation.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem(self, rhs: Self) -> Self {
- self % rhs
- }
- }
-
- doc_comment! {
- concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`.
-Wrapped modulo calculation on unsigned types is
-just the regular remainder calculation.
-There's no way wrapping could ever happen.
-This function exists, so that all operations
-are accounted for in the wrapping operations.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.wrapping_rem(rhs)`.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
- self % rhs
- }
+ pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
+ self % rhs
}
/// Wrapping (modular) negation. Computes `-self`,
self.overflowing_neg().0
}
- doc_comment! {
- concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`,
-where `mask` removes any high-order bits of `rhs` that
-would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-left; the
-RHS of a wrapping shift-left is restricted to the range
-of the type, rather than the bits shifted out of the LHS
-being returned to the other end. The primitive integer
-types all implement a [`rotate_left`](#method.rotate_left) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128);
-assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shl(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
- }
+ /// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
+ /// where `mask` removes any high-order bits of `rhs` that
+ /// would cause the shift to exceed the bitwidth of the type.
+ ///
+ /// Note that this is *not* the same as a rotate-left; the
+ /// RHS of a wrapping shift-left is restricted to the range
+ /// of the type, rather than the bits shifted out of the LHS
+ /// being returned to the other end. The primitive integer
+ /// types all implement a [`rotate_left`](#method.rotate_left) function,
+ /// which may be what you want instead.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128);")]
+ #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);")]
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shl(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
}
}
- doc_comment! {
- concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
-where `mask` removes any high-order bits of `rhs` that
-would cause the shift to exceed the bitwidth of the type.
-
-Note that this is *not* the same as a rotate-right; the
-RHS of a wrapping shift-right is restricted to the range
-of the type, rather than the bits shifted out of the LHS
-being returned to the other end. The primitive integer
-types all implement a [`rotate_right`](#method.rotate_right) function,
-which may be what you want instead.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1);
-assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
-```"),
- #[stable(feature = "num_wrapping", since = "1.2.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_shr(self, rhs: u32) -> Self {
- // SAFETY: the masking by the bitsize of the type ensures that we do not shift
- // out of bounds
- unsafe {
- intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
- }
+ /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
+ /// where `mask` removes any high-order bits of `rhs` that
+ /// would cause the shift to exceed the bitwidth of the type.
+ ///
+ /// Note that this is *not* the same as a rotate-right; the
+ /// RHS of a wrapping shift-right is restricted to the range
+ /// of the type, rather than the bits shifted out of the LHS
+ /// being returned to the other end. The primitive integer
+ /// types all implement a [`rotate_right`](#method.rotate_right) function,
+ /// which may be what you want instead.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1);")]
+ #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);")]
+ /// ```
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_shr(self, rhs: u32) -> Self {
+ // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+ // out of bounds
+ unsafe {
+ intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
}
}
- doc_comment! {
- concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
-wrapping around at the boundary of the type.
-
-# Examples
-
-Basic usage:
+ /// Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
+ /// wrapping around at the boundary of the type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);")]
+ /// assert_eq!(3u8.wrapping_pow(6), 217);
+ /// ```
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);
-assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn wrapping_pow(self, mut exp: u32) -> Self {
- if exp == 0 {
- return 1;
- }
- let mut base = self;
- let mut acc: Self = 1;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- acc = acc.wrapping_mul(base);
- }
- exp /= 2;
- base = base.wrapping_mul(base);
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ acc = acc.wrapping_mul(base);
}
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- acc.wrapping_mul(base)
+ exp /= 2;
+ base = base.wrapping_mul(base);
}
- }
- doc_comment! {
- concat!("Calculates `self` + `rhs`
-
-Returns a tuple of the addition along with a boolean indicating
-whether an arithmetic overflow would occur. If an overflow would
-have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
-assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ acc.wrapping_mul(base)
}
- doc_comment! {
- concat!("Calculates `self` - `rhs`
-
-Returns a tuple of the subtraction along with a boolean indicating
-whether an arithmetic overflow would occur. If an overflow would
-have occurred then the wrapped value is returned.
-
-# Examples
-
-Basic usage
+ /// Calculates `self` + `rhs`
+ ///
+ /// Returns a tuple of the addition along with a boolean indicating
+ /// whether an arithmetic overflow would occur. If an overflow would
+ /// have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
+ }
-```
-", $Feature, "
-assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));
-assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));",
-$EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
- let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
- (a as Self, b)
- }
+ /// Calculates `self` - `rhs`
+ ///
+ /// Returns a tuple of the subtraction along with a boolean indicating
+ /// whether an arithmetic overflow would occur. If an overflow would
+ /// have occurred then the wrapped value is returned.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ ///
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT);
+ (a as Self, b)
}
/// Calculates the multiplication of `self` and `rhs`.
(a as Self, b)
}
- doc_comment! {
- concat!("Calculates the divisor when `self` is divided by `rhs`.
-
-Returns a tuple of the divisor along with a boolean indicating
-whether an arithmetic overflow would occur. Note that for unsigned
-integers overflow never occurs, so the second value is always
-`false`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
- (self / rhs, false)
- }
- }
-
- doc_comment! {
- concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
-
-Returns a tuple of the divisor along with a boolean indicating
-whether an arithmetic overflow would occur. Note that for unsigned
-integers overflow never occurs, so the second value is always
-`false`.
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self.overflowing_div(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));
-```"),
- #[inline]
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
- (self / rhs, false)
- }
+ /// Calculates the divisor when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the divisor along with a boolean indicating
+ /// whether an arithmetic overflow would occur. Note that for unsigned
+ /// integers overflow never occurs, so the second value is always
+ /// `false`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
+ (self / rhs, false)
}
- doc_comment! {
- concat!("Calculates the remainder when `self` is divided by `rhs`.
-
-Returns a tuple of the remainder after dividing along with a boolean
-indicating whether an arithmetic overflow would occur. Note that for
-unsigned integers overflow never occurs, so the second value is
-always `false`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
- (self % rhs, false)
- }
+ /// Calculates the quotient of Euclidean division `self.div_euclid(rhs)`.
+ ///
+ /// Returns a tuple of the divisor along with a boolean indicating
+ /// whether an arithmetic overflow would occur. Note that for unsigned
+ /// integers overflow never occurs, so the second value is always
+ /// `false`.
+ /// Since, for the positive integers, all common
+ /// definitions of division are equal, this
+ /// is exactly equal to `self.overflowing_div(rhs)`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
+ (self / rhs, false)
}
- doc_comment! {
- concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division.
-
-Returns a tuple of the modulo after dividing along with a boolean
-indicating whether an arithmetic overflow would occur. Note that for
-unsigned integers overflow never occurs, so the second value is
-always `false`.
-Since, for the positive integers, all common
-definitions of division are equal, this operation
-is exactly equal to `self.overflowing_rem(rhs)`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage
-
-```
-assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));
-```"),
- #[inline]
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
- (self % rhs, false)
- }
+ /// Calculates the remainder when `self` is divided by `rhs`.
+ ///
+ /// Returns a tuple of the remainder after dividing along with a boolean
+ /// indicating whether an arithmetic overflow would occur. Note that for
+ /// unsigned integers overflow never occurs, so the second value is
+ /// always `false`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
+ (self % rhs, false)
}
- doc_comment! {
- concat!("Negates self in an overflowing fashion.
-
-Returns `!self + 1` using wrapping operations to return the value
-that represents the negation of this unsigned value. Note that for
-positive unsigned values overflow always occurs, but negating 0 does
-not overflow.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));
-assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT),
-", true));", $EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- pub const fn overflowing_neg(self) -> (Self, bool) {
- ((!self).wrapping_add(1), self != 0)
- }
+ /// Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division.
+ ///
+ /// Returns a tuple of the modulo after dividing along with a boolean
+ /// indicating whether an arithmetic overflow would occur. Note that for
+ /// unsigned integers overflow never occurs, so the second value is
+ /// always `false`.
+ /// Since, for the positive integers, all common
+ /// definitions of division are equal, this operation
+ /// is exactly equal to `self.overflowing_rem(rhs)`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
+ (self % rhs, false)
}
- doc_comment! {
- concat!("Shifts self left by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean
-indicating whether the shift value was larger than or equal to the
-number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then
-used to perform the shift.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));
-assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
- }
+ /// Negates self in an overflowing fashion.
+ ///
+ /// Returns `!self + 1` using wrapping operations to return the value
+ /// that represents the negation of this unsigned value. Note that for
+ /// positive unsigned values overflow always occurs, but negating 0 does
+ /// not overflow.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), ", true));")]
+ /// ```
+ #[inline]
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ pub const fn overflowing_neg(self) -> (Self, bool) {
+ ((!self).wrapping_add(1), self != 0)
}
- doc_comment! {
- concat!("Shifts self right by `rhs` bits.
-
-Returns a tuple of the shifted version of self along with a boolean
-indicating whether the shift value was larger than or equal to the
-number of bits. If the shift value is too large, then value is
-masked (N-1) where N is the number of bits, and this value is then
-used to perform the shift.
-
-# Examples
-
-Basic usage
-
-```
-", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
-assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, "
-```"),
- #[stable(feature = "wrapping", since = "1.7.0")]
- #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
- (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
- }
+ /// Shifts self left by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean
+ /// indicating whether the shift value was larger than or equal to the
+ /// number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then
+ /// used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));")]
+ #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
}
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-Returns a tuple of the exponentiation along with a bool indicating
-whether an overflow happened.
-
-# Examples
+ /// Shifts self right by `rhs` bits.
+ ///
+ /// Returns a tuple of the shifted version of self along with a boolean
+ /// indicating whether the shift value was larger than or equal to the
+ /// number of bits. If the shift value is too large, then value is
+ /// masked (N-1) where N is the number of bits, and this value is then
+ /// used to perform the shift.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")]
+ #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));")]
+ /// ```
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+ }
-Basic usage:
+ /// Raises self to the power of `exp`, using exponentiation by squaring.
+ ///
+ /// Returns a tuple of the exponentiation along with a bool indicating
+ /// whether an overflow happened.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));")]
+ /// assert_eq!(3u8.overflowing_pow(6), (217, true));
+ /// ```
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+ if exp == 0{
+ return (1,false);
+ }
+ let mut base = self;
+ let mut acc: Self = 1;
+ let mut overflown = false;
+ // Scratch space for storing results of overflowing_mul.
+ let mut r;
-```
-", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));
-assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
-```"),
- #[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
- if exp == 0{
- return (1,false);
- }
- let mut base = self;
- let mut acc: Self = 1;
- let mut overflown = false;
- // Scratch space for storing results of overflowing_mul.
- let mut r;
-
- while exp > 1 {
- if (exp & 1) == 1 {
- r = acc.overflowing_mul(base);
- acc = r.0;
- overflown |= r.1;
- }
- exp /= 2;
- r = base.overflowing_mul(base);
- base = r.0;
+ while exp > 1 {
+ if (exp & 1) == 1 {
+ r = acc.overflowing_mul(base);
+ acc = r.0;
overflown |= r.1;
}
-
- // since exp!=0, finally the exp must be 1.
- // Deal with the final bit of the exponent separately, since
- // squaring the base afterwards is not necessary and may cause a
- // needless overflow.
- r = acc.overflowing_mul(base);
- r.1 |= overflown;
-
- r
+ exp /= 2;
+ r = base.overflowing_mul(base);
+ base = r.0;
+ overflown |= r.1;
}
- }
-
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-# Examples
+ // since exp!=0, finally the exp must be 1.
+ // Deal with the final bit of the exponent separately, since
+ // squaring the base afterwards is not necessary and may cause a
+ // needless overflow.
+ r = acc.overflowing_mul(base);
+ r.1 |= overflown;
-Basic usage:
+ r
+ }
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
-```"),
+ /// Raises self to the power of `exp`, using exponentiation by squaring.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".pow(5), 32);")]
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
// needless overflow.
acc * base
}
- }
-
- doc_comment! {
- concat!("Performs Euclidean division.
-
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self / rhs`.
-
-# Panics
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn div_euclid(self, rhs: Self) -> Self {
- self / rhs
- }
+ /// Performs Euclidean division.
+ ///
+ /// Since, for the positive integers, all common
+ /// definitions of division are equal, this
+ /// is exactly equal to `self / rhs`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn div_euclid(self, rhs: Self) -> Self {
+ self / rhs
}
- doc_comment! {
- concat!("Calculates the least remainder of `self (mod rhs)`.
-
-Since, for the positive integers, all common
-definitions of division are equal, this
-is exactly equal to `self % rhs`.
-
-# Panics
-
-This function will panic if `rhs` is 0.
-
-# Examples
-
-Basic usage:
-
-```
-assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type
-```"),
- #[stable(feature = "euclidean_division", since = "1.38.0")]
- #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn rem_euclid(self, rhs: Self) -> Self {
- self % rhs
- }
+ /// Calculates the least remainder of `self (mod rhs)`.
+ ///
+ /// Since, for the positive integers, all common
+ /// definitions of division are equal, this
+ /// is exactly equal to `self % rhs`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `rhs` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type")]
+ /// ```
+ #[stable(feature = "euclidean_division", since = "1.38.0")]
+ #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn rem_euclid(self, rhs: Self) -> Self {
+ self % rhs
}
- doc_comment! {
- concat!("Returns `true` if and only if `self == 2^k` for some `k`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two());
-assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")]
- #[inline]
- pub const fn is_power_of_two(self) -> bool {
- self.count_ones() == 1
- }
+ /// Returns `true` if and only if `self == 2^k` for some `k`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert!(16", stringify!($SelfT), ".is_power_of_two());")]
+ #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_power_of_two());")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")]
+ #[inline]
+ pub const fn is_power_of_two(self) -> bool {
+ self.count_ones() == 1
}
// Returns one less than next power of two.
<$SelfT>::MAX >> z
}
- doc_comment! {
- concat!("Returns the smallest power of two greater than or equal to `self`.
-
-When return value overflows (i.e., `self > (1 << (N-1))` for type
-`uN`), it panics in debug mode and return value is wrapped to 0 in
-release mode (the only situation in which method can return 0).
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);
-assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
-```"),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- #[inline]
- #[rustc_inherit_overflow_checks]
- pub const fn next_power_of_two(self) -> Self {
- self.one_less_than_next_power_of_two() + 1
- }
- }
-
- doc_comment! {
- concat!("Returns the smallest power of two greater than or equal to `n`. If
-the next power of two is greater than the type's maximum value,
-`None` is returned, otherwise the power of two is wrapped in `Some`.
-
-# Examples
-
-Basic usage:
-
-```
-", $Feature, "assert_eq!(2", stringify!($SelfT),
-".checked_next_power_of_two(), Some(2));
-assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4));
-assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);",
-$EndFeature, "
-```"),
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- pub const fn checked_next_power_of_two(self) -> Option<Self> {
- self.one_less_than_next_power_of_two().checked_add(1)
- }
+ /// Returns the smallest power of two greater than or equal to `self`.
+ ///
+ /// When return value overflows (i.e., `self > (1 << (N-1))` for type
+ /// `uN`), it panics in debug mode and return value is wrapped to 0 in
+ /// release mode (the only situation in which method can return 0).
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);")]
+ #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);")]
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ pub const fn next_power_of_two(self) -> Self {
+ self.one_less_than_next_power_of_two() + 1
}
- doc_comment! {
- concat!("Returns the smallest power of two greater than or equal to `n`. If
-the next power of two is greater than the type's maximum value,
-the return value is wrapped to `0`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_next_power_of_two)]
-", $Feature, "
-assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2);
-assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4);
-assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);",
-$EndFeature, "
-```"),
- #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
- reason = "needs decision on wrapping behaviour")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
- pub const fn wrapping_next_power_of_two(self) -> Self {
- self.one_less_than_next_power_of_two().wrapping_add(1)
- }
+ /// Returns the smallest power of two greater than or equal to `n`. If
+ /// the next power of two is greater than the type's maximum value,
+ /// `None` is returned, otherwise the power of two is wrapped in `Some`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_next_power_of_two(), Some(2));")]
+ #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);")]
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ pub const fn checked_next_power_of_two(self) -> Option<Self> {
+ self.one_less_than_next_power_of_two().checked_add(1)
}
- doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-big-endian (network) byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
-assert_eq!(bytes, ", $be_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_be().to_ne_bytes()
- }
+ /// Returns the smallest power of two greater than or equal to `n`. If
+ /// the next power of two is greater than the type's maximum value,
+ /// the return value is wrapped to `0`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_next_power_of_two)]
+ ///
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2);")]
+ #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4);")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);")]
+ /// ```
+ #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
+ reason = "needs decision on wrapping behaviour")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ pub const fn wrapping_next_power_of_two(self) -> Self {
+ self.one_less_than_next_power_of_two().wrapping_add(1)
}
- doc_comment! {
- concat!("Return the memory representation of this integer as a byte array in
-little-endian byte order.
-",
-$to_xe_bytes_doc,
-"
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
-assert_eq!(bytes, ", $le_bytes, ");
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
- self.to_le().to_ne_bytes()
- }
+ /// Return the memory representation of this integer as a byte array in
+ /// big-endian (network) byte order.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();")]
+ #[doc = concat!("assert_eq!(bytes, ", $be_bytes, ");")]
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_be().to_ne_bytes()
}
- doc_comment! {
- concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-As the target platform's native endianness is used, portable code
-should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
-instead.
-",
-$to_xe_bytes_doc,
-"
-[`to_be_bytes`]: #method.to_be_bytes
-[`to_le_bytes`]: #method.to_le_bytes
-
-# Examples
-
-```
-let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();
-assert_eq!(
- bytes,
- if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
- } else {
- ", $le_bytes, "
- }
-);
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute them to arrays of bytes
- #[rustc_allow_const_fn_unstable(const_fn_transmute)]
- #[inline]
- pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { mem::transmute(self) }
- }
+ /// Return the memory representation of this integer as a byte array in
+ /// little-endian byte order.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();")]
+ #[doc = concat!("assert_eq!(bytes, ", $le_bytes, ");")]
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_le().to_ne_bytes()
}
- doc_comment! {
- concat!("
-Return the memory representation of this integer as a byte array in
-native byte order.
-
-[`to_ne_bytes`] should be preferred over this whenever possible.
-
-[`to_ne_bytes`]: #method.to_ne_bytes
-",
-
-"
-# Examples
-
-```
-#![feature(num_as_ne_bytes)]
-let num = ", $swap_op, stringify!($SelfT), ";
-let bytes = num.as_ne_bytes();
-assert_eq!(
- bytes,
- if cfg!(target_endian = \"big\") {
- &", $be_bytes, "
- } else {
- &", $le_bytes, "
- }
-);
-```"),
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { &*(self as *const Self as *const _) }
- }
+ /// Return the memory representation of this integer as a byte array in
+ /// native byte order.
+ ///
+ /// As the target platform's native endianness is used, portable code
+ /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
+ /// instead.
+ ///
+ #[doc = $to_xe_bytes_doc]
+ ///
+ /// [`to_be_bytes`]: #method.to_be_bytes
+ /// [`to_le_bytes`]: #method.to_le_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes();")]
+ /// assert_eq!(
+ /// bytes,
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" ", $be_bytes)]
+ /// } else {
+ #[doc = concat!(" ", $le_bytes)]
+ /// }
+ /// );
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute them to arrays of bytes
+ #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ // SAFETY: integers are plain old datatypes so we can always transmute them to
+ // arrays of bytes
+ unsafe { mem::transmute(self) }
}
- doc_comment! {
- concat!("Create a native endian integer value from its representation
-as a byte array in big endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_be(Self::from_ne_bytes(bytes))
- }
+ /// Return the memory representation of this integer as a byte array in
+ /// native byte order.
+ ///
+ /// [`to_ne_bytes`] should be preferred over this whenever possible.
+ ///
+ /// [`to_ne_bytes`]: #method.to_ne_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_as_ne_bytes)]
+ #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
+ /// let bytes = num.as_ne_bytes();
+ /// assert_eq!(
+ /// bytes,
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" &", $be_bytes)]
+ /// } else {
+ #[doc = concat!(" &", $le_bytes)]
+ /// }
+ /// );
+ /// ```
+ #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+ #[inline]
+ pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
+ // SAFETY: integers are plain old datatypes so we can always transmute them to
+ // arrays of bytes
+ unsafe { &*(self as *const Self as *const _) }
}
- doc_comment! {
- concat!("
-Create a native endian integer value from its representation
-as a byte array in little endian.
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- #[inline]
- pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- Self::from_le(Self::from_ne_bytes(bytes))
- }
+ /// Create a native endian integer value from its representation
+ /// as a byte array in big endian.
+ ///
+ #[doc = $from_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");")]
+ #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+ /// ```
+ ///
+ /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ ///
+ #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+ #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+ /// *input = rest;
+ #[doc = concat!(" ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")]
+ /// }
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_be(Self::from_ne_bytes(bytes))
}
- doc_comment! {
- concat!("Create a native endian integer value from its memory representation
-as a byte array in native endianness.
-
-As the target platform's native endianness is used, portable code
-likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
-appropriate instead.
-
-[`from_be_bytes`]: #method.from_be_bytes
-[`from_le_bytes`]: #method.from_le_bytes
-",
-$from_xe_bytes_doc,
-"
-# Examples
-
-```
-let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {
- ", $be_bytes, "
-} else {
- ", $le_bytes, "
-});
-assert_eq!(value, ", $swap_op, ");
-```
-
-When starting from a slice rather than an array, fallible conversion APIs can be used:
-
-```
-use std::convert::TryInto;
-
-fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
- let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
- *input = rest;
- ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
-}
-```"),
- #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
- #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
- // SAFETY: const sound because integers are plain old datatypes so we can always
- // transmute to them
- #[rustc_allow_const_fn_unstable(const_fn_transmute)]
- #[inline]
- pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- // SAFETY: integers are plain old datatypes so we can always transmute to them
- unsafe { mem::transmute(bytes) }
- }
+ /// Create a native endian integer value from its representation
+ /// as a byte array in little endian.
+ ///
+ #[doc = $from_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");")]
+ #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+ /// ```
+ ///
+ /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ ///
+ #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+ #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+ /// *input = rest;
+ #[doc = concat!(" ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")]
+ /// }
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ #[inline]
+ pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_le(Self::from_ne_bytes(bytes))
}
- doc_comment! {
- concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause compilation warning,
-new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead.
-
-Returns the smallest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_promotable]
- #[inline(always)]
- #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- pub const fn min_value() -> Self { Self::MIN }
+ /// Create a native endian integer value from its memory representation
+ /// as a byte array in native endianness.
+ ///
+ /// As the target platform's native endianness is used, portable code
+ /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
+ /// appropriate instead.
+ ///
+ /// [`from_be_bytes`]: #method.from_be_bytes
+ /// [`from_le_bytes`]: #method.from_le_bytes
+ ///
+ #[doc = $from_xe_bytes_doc]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!("let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") {")]
+ #[doc = concat!(" ", $be_bytes, "")]
+ /// } else {
+ #[doc = concat!(" ", $le_bytes, "")]
+ /// });
+ #[doc = concat!("assert_eq!(value, ", $swap_op, ");")]
+ /// ```
+ ///
+ /// When starting from a slice rather than an array, fallible conversion APIs can be used:
+ ///
+ /// ```
+ /// use std::convert::TryInto;
+ ///
+ #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
+ #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
+ /// *input = rest;
+ #[doc = concat!(" ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")]
+ /// }
+ /// ```
+ #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
+ // SAFETY: const sound because integers are plain old datatypes so we can always
+ // transmute to them
+ #[rustc_allow_const_fn_unstable(const_fn_transmute)]
+ #[inline]
+ pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ // SAFETY: integers are plain old datatypes so we can always transmute to them
+ unsafe { mem::transmute(bytes) }
}
- doc_comment! {
- concat!("**This method is soft-deprecated.**
-
-Although using it won’t cause compilation warning,
-new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead.
+ /// **This method is soft-deprecated.**
+ ///
+ /// Although using it won’t cause compilation warning, new code should use
+ #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")]
+ /// instead.
+ ///
+ /// Returns the smallest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_promotable]
+ #[inline(always)]
+ #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+ pub const fn min_value() -> Self { Self::MIN }
-Returns the largest value that can be represented by this integer type."),
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_promotable]
- #[inline(always)]
- #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- pub const fn max_value() -> Self { Self::MAX }
- }
+ /// **This method is soft-deprecated.**
+ ///
+ /// Although using it won’t cause compilation warning, new code should use
+ #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")]
+ /// instead.
+ ///
+ /// Returns the largest value that can be represented by this integer type.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_promotable]
+ #[inline(always)]
+ #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
+ pub const fn max_value() -> Self { Self::MAX }
}
}
macro_rules! wrapping_int_impl {
($($t:ty)*) => ($(
impl Wrapping<$t> {
- doc_comment! {
- concat!("Returns the smallest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(<Wrapping<", stringify!($t), ">>::MIN, Wrapping(", stringify!($t), "::MIN));
-```"),
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const MIN: Self = Self(<$t>::MIN);
- }
-
- doc_comment! {
- concat!("Returns the largest value that can be represented by this integer type.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(<Wrapping<", stringify!($t), ">>::MAX, Wrapping(", stringify!($t), "::MAX));
-```"),
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const MAX: Self = Self(<$t>::MAX);
- }
-
- doc_comment! {
- concat!("Returns the number of ones in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
+ /// Returns the smallest value that can be represented by this integer type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert_eq!(<Wrapping<", stringify!($t), ">>::MIN, Wrapping(", stringify!($t), "::MIN));")]
+ /// ```
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const MIN: Self = Self(<$t>::MIN);
-let n = Wrapping(0b01001100", stringify!($t), ");
+ /// Returns the largest value that can be represented by this integer type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert_eq!(<Wrapping<", stringify!($t), ">>::MAX, Wrapping(", stringify!($t), "::MAX));")]
+ /// ```
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const MAX: Self = Self(<$t>::MAX);
-assert_eq!(n.count_ones(), 3);
-```"),
- #[inline]
- #[doc(alias = "popcount")]
- #[doc(alias = "popcnt")]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn count_ones(self) -> u32 {
- self.0.count_ones()
- }
+ /// Returns the number of ones in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(0b01001100", stringify!($t), ");")]
+ ///
+ /// assert_eq!(n.count_ones(), 3);
+ /// ```
+ #[inline]
+ #[doc(alias = "popcount")]
+ #[doc(alias = "popcnt")]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn count_ones(self) -> u32 {
+ self.0.count_ones()
}
- doc_comment! {
- concat!("Returns the number of zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(!0", stringify!($t), ").count_zeros(), 0);
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn count_zeros(self) -> u32 {
- self.0.count_zeros()
- }
+ /// Returns the number of zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert_eq!(Wrapping(!0", stringify!($t), ").count_zeros(), 0);")]
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn count_zeros(self) -> u32 {
+ self.0.count_zeros()
}
- doc_comment! {
- concat!("Returns the number of trailing zeros in the binary representation
-of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0b0101000", stringify!($t), ");
-
-assert_eq!(n.trailing_zeros(), 3);
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn trailing_zeros(self) -> u32 {
- self.0.trailing_zeros()
- }
+ /// Returns the number of trailing zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(0b0101000", stringify!($t), ");")]
+ ///
+ /// assert_eq!(n.trailing_zeros(), 3);
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn trailing_zeros(self) -> u32 {
+ self.0.trailing_zeros()
}
/// Shifts the bits to the left by a specified amount, `n`,
Wrapping(self.0.reverse_bits())
}
- doc_comment! {
- concat!("Converts an integer from big endian to the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n)
-} else {
- assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n.swap_bytes())
-}
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn from_be(x: Self) -> Self {
- Wrapping(<$t>::from_be(x.0))
- }
+ /// Converts an integer from big endian to the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(<Wrapping<", stringify!($t), ">>::from_be(n), n.swap_bytes())")]
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn from_be(x: Self) -> Self {
+ Wrapping(<$t>::from_be(x.0))
}
- doc_comment! {
- concat!("Converts an integer from little endian to the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n)
-} else {
- assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n.swap_bytes())
-}
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn from_le(x: Self) -> Self {
- Wrapping(<$t>::from_le(x.0))
- }
+ /// Converts an integer from little endian to the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ #[doc = concat!(" assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(<Wrapping<", stringify!($t), ">>::from_le(n), n.swap_bytes())")]
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn from_le(x: Self) -> Self {
+ Wrapping(<$t>::from_le(x.0))
}
- doc_comment! {
- concat!("Converts `self` to big endian from the target's endianness.
-
-On big endian this is a no-op. On little endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"big\") {
- assert_eq!(n.to_be(), n)
-} else {
- assert_eq!(n.to_be(), n.swap_bytes())
-}
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn to_be(self) -> Self {
- Wrapping(self.0.to_be())
- }
+ /// Converts `self` to big endian from the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ /// assert_eq!(n.to_be(), n)
+ /// } else {
+ /// assert_eq!(n.to_be(), n.swap_bytes())
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn to_be(self) -> Self {
+ Wrapping(self.0.to_be())
}
- doc_comment! {
- concat!("Converts `self` to little endian from the target's endianness.
-
-On little endian this is a no-op. On big endian the bytes are
-swapped.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(0x1A", stringify!($t), ");
-
-if cfg!(target_endian = \"little\") {
- assert_eq!(n.to_le(), n)
-} else {
- assert_eq!(n.to_le(), n.swap_bytes())
-}
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn to_le(self) -> Self {
- Wrapping(self.0.to_le())
- }
+ /// Converts `self` to little endian from the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(0x1A", stringify!($t), ");")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ /// assert_eq!(n.to_le(), n)
+ /// } else {
+ /// assert_eq!(n.to_le(), n.swap_bytes())
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn to_le(self) -> Self {
+ Wrapping(self.0.to_le())
}
- doc_comment! {
- concat!("Raises self to the power of `exp`, using exponentiation by squaring.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(3", stringify!($t), ").pow(4), Wrapping(81));
-```
-
-Results that are too large are wrapped:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(3i8).pow(5), Wrapping(-13));
-assert_eq!(Wrapping(3i8).pow(6), Wrapping(-39));
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn pow(self, exp: u32) -> Self {
- Wrapping(self.0.wrapping_pow(exp))
- }
+ /// Raises self to the power of `exp`, using exponentiation by squaring.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert_eq!(Wrapping(3", stringify!($t), ").pow(4), Wrapping(81));")]
+ /// ```
+ ///
+ /// Results that are too large are wrapped:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ /// assert_eq!(Wrapping(3i8).pow(5), Wrapping(-13));
+ /// assert_eq!(Wrapping(3i8).pow(6), Wrapping(-39));
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub fn pow(self, exp: u32) -> Self {
+ Wrapping(self.0.wrapping_pow(exp))
}
}
)*)
macro_rules! wrapping_int_impl_signed {
($($t:ty)*) => ($(
impl Wrapping<$t> {
- doc_comment! {
- concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(", stringify!($t), "::MAX) >> 2;
-
-assert_eq!(n.leading_zeros(), 3);
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn leading_zeros(self) -> u32 {
- self.0.leading_zeros()
- }
+ /// Returns the number of leading zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(", stringify!($t), "::MAX) >> 2;")]
+ ///
+ /// assert_eq!(n.leading_zeros(), 3);
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn leading_zeros(self) -> u32 {
+ self.0.leading_zeros()
}
- doc_comment! {
- concat!("Computes the absolute value of `self`, wrapping around at
-the boundary of the type.
-
-The only case where such wrapping can occur is when one takes the absolute value of the negative
-minimal value for the type this is a positive value that is too large to represent in the type. In
-such a case, this function returns `MIN` itself.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(100", stringify!($t), ").abs(), Wrapping(100));
-assert_eq!(Wrapping(-100", stringify!($t), ").abs(), Wrapping(100));
-assert_eq!(Wrapping(", stringify!($t), "::MIN).abs(), Wrapping(", stringify!($t), "::MIN));
-assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8);
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn abs(self) -> Wrapping<$t> {
- Wrapping(self.0.wrapping_abs())
- }
+ /// Computes the absolute value of `self`, wrapping around at
+ /// the boundary of the type.
+ ///
+ /// The only case where such wrapping can occur is when one takes the absolute value of the negative
+ /// minimal value for the type this is a positive value that is too large to represent in the type. In
+ /// such a case, this function returns `MIN` itself.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert_eq!(Wrapping(100", stringify!($t), ").abs(), Wrapping(100));")]
+ #[doc = concat!("assert_eq!(Wrapping(-100", stringify!($t), ").abs(), Wrapping(100));")]
+ #[doc = concat!("assert_eq!(Wrapping(", stringify!($t), "::MIN).abs(), Wrapping(", stringify!($t), "::MIN));")]
+ /// assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8);
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub fn abs(self) -> Wrapping<$t> {
+ Wrapping(self.0.wrapping_abs())
}
- doc_comment! {
- concat!("Returns a number representing sign of `self`.
-
- - `0` if the number is zero
- - `1` if the number is positive
- - `-1` if the number is negative
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(10", stringify!($t), ").signum(), Wrapping(1));
-assert_eq!(Wrapping(0", stringify!($t), ").signum(), Wrapping(0));
-assert_eq!(Wrapping(-10", stringify!($t), ").signum(), Wrapping(-1));
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn signum(self) -> Wrapping<$t> {
- Wrapping(self.0.signum())
- }
+ /// Returns a number representing sign of `self`.
+ ///
+ /// - `0` if the number is zero
+ /// - `1` if the number is positive
+ /// - `-1` if the number is negative
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert_eq!(Wrapping(10", stringify!($t), ").signum(), Wrapping(1));")]
+ #[doc = concat!("assert_eq!(Wrapping(0", stringify!($t), ").signum(), Wrapping(0));")]
+ #[doc = concat!("assert_eq!(Wrapping(-10", stringify!($t), ").signum(), Wrapping(-1));")]
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub fn signum(self) -> Wrapping<$t> {
+ Wrapping(self.0.signum())
}
- doc_comment! {
- concat!("Returns `true` if `self` is positive and `false` if the number is zero or
-negative.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert!(Wrapping(10", stringify!($t), ").is_positive());
-assert!(!Wrapping(-10", stringify!($t), ").is_positive());
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn is_positive(self) -> bool {
- self.0.is_positive()
- }
+ /// Returns `true` if `self` is positive and `false` if the number is zero or
+ /// negative.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert!(Wrapping(10", stringify!($t), ").is_positive());")]
+ #[doc = concat!("assert!(!Wrapping(-10", stringify!($t), ").is_positive());")]
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn is_positive(self) -> bool {
+ self.0.is_positive()
}
- doc_comment! {
- concat!("Returns `true` if `self` is negative and `false` if the number is zero or
-positive.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert!(Wrapping(-10", stringify!($t), ").is_negative());
-assert!(!Wrapping(10", stringify!($t), ").is_negative());
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn is_negative(self) -> bool {
- self.0.is_negative()
- }
+ /// Returns `true` if `self` is negative and `false` if the number is zero or
+ /// positive.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert!(Wrapping(-10", stringify!($t), ").is_negative());")]
+ #[doc = concat!("assert!(!Wrapping(10", stringify!($t), ").is_negative());")]
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn is_negative(self) -> bool {
+ self.0.is_negative()
}
}
)*)
macro_rules! wrapping_int_impl_unsigned {
($($t:ty)*) => ($(
impl Wrapping<$t> {
- doc_comment! {
- concat!("Returns the number of leading zeros in the binary representation of `self`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-let n = Wrapping(", stringify!($t), "::MAX) >> 2;
-
-assert_eq!(n.leading_zeros(), 2);
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub const fn leading_zeros(self) -> u32 {
- self.0.leading_zeros()
- }
+ /// Returns the number of leading zeros in the binary representation of `self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("let n = Wrapping(", stringify!($t), "::MAX) >> 2;")]
+ ///
+ /// assert_eq!(n.leading_zeros(), 2);
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub const fn leading_zeros(self) -> u32 {
+ self.0.leading_zeros()
}
- doc_comment! {
- concat!("Returns `true` if and only if `self == 2^k` for some `k`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_int_impl)]
-use std::num::Wrapping;
-
-assert!(Wrapping(16", stringify!($t), ").is_power_of_two());
-assert!(!Wrapping(10", stringify!($t), ").is_power_of_two());
-```"),
- #[inline]
- #[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn is_power_of_two(self) -> bool {
- self.0.is_power_of_two()
- }
+ /// Returns `true` if and only if `self == 2^k` for some `k`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_int_impl)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert!(Wrapping(16", stringify!($t), ").is_power_of_two());")]
+ #[doc = concat!("assert!(!Wrapping(10", stringify!($t), ").is_power_of_two());")]
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_int_impl", issue = "32463")]
+ pub fn is_power_of_two(self) -> bool {
+ self.0.is_power_of_two()
}
- doc_comment! {
- concat!("Returns the smallest power of two greater than or equal to `self`.
-
-When return value overflows (i.e., `self > (1 << (N-1))` for type
-`uN`), overflows to `2^N = 0`.
-
-# Examples
-
-Basic usage:
-
-```
-#![feature(wrapping_next_power_of_two)]
-use std::num::Wrapping;
-
-assert_eq!(Wrapping(2", stringify!($t), ").next_power_of_two(), Wrapping(2));
-assert_eq!(Wrapping(3", stringify!($t), ").next_power_of_two(), Wrapping(4));
-assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0));
-```"),
- #[inline]
- #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
- reason = "needs decision on wrapping behaviour")]
- pub fn next_power_of_two(self) -> Self {
- Wrapping(self.0.wrapping_next_power_of_two())
- }
+ /// Returns the smallest power of two greater than or equal to `self`.
+ ///
+ /// When return value overflows (i.e., `self > (1 << (N-1))` for type
+ /// `uN`), overflows to `2^N = 0`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(wrapping_next_power_of_two)]
+ /// use std::num::Wrapping;
+ ///
+ #[doc = concat!("assert_eq!(Wrapping(2", stringify!($t), ").next_power_of_two(), Wrapping(2));")]
+ #[doc = concat!("assert_eq!(Wrapping(3", stringify!($t), ").next_power_of_two(), Wrapping(4));")]
+ #[doc = concat!("assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0));")]
+ /// ```
+ #[inline]
+ #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
+ reason = "needs decision on wrapping behaviour")]
+ pub fn next_power_of_two(self) -> Self {
+ Wrapping(self.0.wrapping_next_power_of_two())
}
}
)*)
///
/// # Safety
///
- /// The resulting pointer does not need to be in bounds, but it is
- /// potentially hazardous to dereference (which requires `unsafe`).
+ /// This operation itself is always safe, but using the resulting pointer is not.
///
- /// In particular, the resulting pointer remains attached to the same allocated
- /// object that `self` points to. It may *not* be used to access a
- /// different allocated object. Note that in Rust,
- /// every (stack-allocated) variable is considered a separate allocated object.
+ /// The resulting pointer remains attached to the same allocated object that `self` points to.
+ /// It may *not* be used to access a different allocated object. Note that in Rust, every
+ /// (stack-allocated) variable is considered a separate allocated object.
///
- /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
- /// is *not* the same as `y`, and dereferencing it is undefined behavior
- /// unless `x` and `y` point into the same allocated object.
+ /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
+ /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+ /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+ /// `x` and `y` point into the same allocated object.
///
- /// Compared to [`offset`], this method basically delays the requirement of staying
- /// within the same allocated object: [`offset`] is immediate Undefined Behavior when
- /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
- /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
- /// better and is thus preferable in performance-sensitive code.
+ /// Compared to [`offset`], this method basically delays the requirement of staying within the
+ /// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
+ /// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
+ /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
+ /// can be optimized better and is thus preferable in performance-sensitive code.
+ ///
+ /// The delayed check only considers the value of the pointer that was dereferenced, not the
+ /// intermediate values used during the computation of the final result. For example,
+ /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
+ /// words, leaving the allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// # Safety
///
- /// The resulting pointer does not need to be in bounds, but it is
- /// potentially hazardous to dereference (which requires `unsafe`).
+ /// This operation itself is always safe, but using the resulting pointer is not.
+ ///
+ /// The resulting pointer remains attached to the same allocated object that `self` points to.
+ /// It may *not* be used to access a different allocated object. Note that in Rust, every
+ /// (stack-allocated) variable is considered a separate allocated object.
+ ///
+ /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
+ /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+ /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+ /// `x` and `y` point into the same allocated object.
///
- /// In particular, the resulting pointer remains attached to the same allocated
- /// object that `self` points to. It may *not* be used to access a
- /// different allocated object. Note that in Rust,
- /// every (stack-allocated) variable is considered a separate allocated object.
+ /// Compared to [`add`], this method basically delays the requirement of staying within the
+ /// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
+ /// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
+ /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
+ /// can be optimized better and is thus preferable in performance-sensitive code.
///
- /// Compared to [`add`], this method basically delays the requirement of staying
- /// within the same allocated object: [`add`] is immediate Undefined Behavior when
- /// crossing object boundaries; `wrapping_add` produces a pointer but still leads
- /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
- /// better and is thus preferable in performance-sensitive code.
+ /// The delayed check only considers the value of the pointer that was dereferenced, not the
+ /// intermediate values used during the computation of the final result. For example,
+ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+ /// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// # Safety
///
- /// The resulting pointer does not need to be in bounds, but it is
- /// potentially hazardous to dereference (which requires `unsafe`).
+ /// This operation itself is always safe, but using the resulting pointer is not.
+ ///
+ /// The resulting pointer remains attached to the same allocated object that `self` points to.
+ /// It may *not* be used to access a different allocated object. Note that in Rust, every
+ /// (stack-allocated) variable is considered a separate allocated object.
+ ///
+ /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
+ /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+ /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+ /// `x` and `y` point into the same allocated object.
///
- /// In particular, the resulting pointer remains attached to the same allocated
- /// object that `self` points to. It may *not* be used to access a
- /// different allocated object. Note that in Rust,
- /// every (stack-allocated) variable is considered a separate allocated object.
+ /// Compared to [`sub`], this method basically delays the requirement of staying within the
+ /// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
+ /// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
+ /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
+ /// can be optimized better and is thus preferable in performance-sensitive code.
///
- /// Compared to [`sub`], this method basically delays the requirement of staying
- /// within the same allocated object: [`sub`] is immediate Undefined Behavior when
- /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
- /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
- /// better and is thus preferable in performance-sensitive code.
+ /// The delayed check only considers the value of the pointer that was dereferenced, not the
+ /// intermediate values used during the computation of the final result. For example,
+ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+ /// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`ptr::read`]: crate::ptr::read()
#[stable(feature = "pointer_methods", since = "1.26.0")]
+ #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
#[inline]
- pub unsafe fn read(self) -> T
+ pub const unsafe fn read(self) -> T
where
T: Sized,
{
///
/// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
#[stable(feature = "pointer_methods", since = "1.26.0")]
+ #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
#[inline]
- pub unsafe fn read_unaligned(self) -> T
+ pub const unsafe fn read_unaligned(self) -> T
where
T: Sized,
{
/// [valid]: self#safety
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn read<T>(src: *const T) -> T {
+#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+pub const unsafe fn read<T>(src: *const T) -> T {
// `copy_nonoverlapping` takes care of debug_assert.
let mut tmp = MaybeUninit::<T>::uninit();
// SAFETY: the caller must guarantee that `src` is valid for reads.
/// ```
#[inline]
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
-pub unsafe fn read_unaligned<T>(src: *const T) -> T {
+#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
// `copy_nonoverlapping` takes care of debug_assert.
let mut tmp = MaybeUninit::<T>::uninit();
// SAFETY: the caller must guarantee that `src` is valid for reads.
///
/// # Safety
///
- /// The resulting pointer does not need to be in bounds, but it is
- /// potentially hazardous to dereference (which requires `unsafe`).
+ /// This operation itself is always safe, but using the resulting pointer is not.
///
- /// In particular, the resulting pointer remains attached to the same allocated
- /// object that `self` points to. It may *not* be used to access a
- /// different allocated object. Note that in Rust,
- /// every (stack-allocated) variable is considered a separate allocated object.
+ /// The resulting pointer remains attached to the same allocated object that `self` points to.
+ /// It may *not* be used to access a different allocated object. Note that in Rust, every
+ /// (stack-allocated) variable is considered a separate allocated object.
///
- /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
- /// is *not* the same as `y`, and dereferencing it is undefined behavior
- /// unless `x` and `y` point into the same allocated object.
+ /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
+ /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+ /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+ /// `x` and `y` point into the same allocated object.
///
- /// Compared to [`offset`], this method basically delays the requirement of staying
- /// within the same allocated object: [`offset`] is immediate Undefined Behavior when
- /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
- /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
- /// better and is thus preferable in performance-sensitive code.
+ /// Compared to [`offset`], this method basically delays the requirement of staying within the
+ /// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
+ /// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
+ /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
+ /// can be optimized better and is thus preferable in performance-sensitive code.
+ ///
+ /// The delayed check only considers the value of the pointer that was dereferenced, not the
+ /// intermediate values used during the computation of the final result. For example,
+ /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
+ /// words, leaving the allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// # Safety
///
- /// The resulting pointer does not need to be in bounds, but it is
- /// potentially hazardous to dereference (which requires `unsafe`).
+ /// This operation itself is always safe, but using the resulting pointer is not.
+ ///
+ /// The resulting pointer remains attached to the same allocated object that `self` points to.
+ /// It may *not* be used to access a different allocated object. Note that in Rust, every
+ /// (stack-allocated) variable is considered a separate allocated object.
+ ///
+ /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
+ /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+ /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+ /// `x` and `y` point into the same allocated object.
///
- /// In particular, the resulting pointer remains attached to the same allocated
- /// object that `self` points to. It may *not* be used to access a
- /// different allocated object. Note that in Rust,
- /// every (stack-allocated) variable is considered a separate allocated object.
+ /// Compared to [`add`], this method basically delays the requirement of staying within the
+ /// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
+ /// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
+ /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
+ /// can be optimized better and is thus preferable in performance-sensitive code.
///
- /// Compared to [`add`], this method basically delays the requirement of staying
- /// within the same allocated object: [`add`] is immediate Undefined Behavior when
- /// crossing object boundaries; `wrapping_add` produces a pointer but still leads
- /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
- /// better and is thus preferable in performance-sensitive code.
+ /// The delayed check only considers the value of the pointer that was dereferenced, not the
+ /// intermediate values used during the computation of the final result. For example,
+ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+ /// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// # Safety
///
- /// The resulting pointer does not need to be in bounds, but it is
- /// potentially hazardous to dereference (which requires `unsafe`).
+ /// This operation itself is always safe, but using the resulting pointer is not.
+ ///
+ /// The resulting pointer remains attached to the same allocated object that `self` points to.
+ /// It may *not* be used to access a different allocated object. Note that in Rust, every
+ /// (stack-allocated) variable is considered a separate allocated object.
+ ///
+ /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
+ /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
+ /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
+ /// `x` and `y` point into the same allocated object.
///
- /// In particular, the resulting pointer remains attached to the same allocated
- /// object that `self` points to. It may *not* be used to access a
- /// different allocated object. Note that in Rust,
- /// every (stack-allocated) variable is considered a separate allocated object.
+ /// Compared to [`sub`], this method basically delays the requirement of staying within the
+ /// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
+ /// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
+ /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
+ /// can be optimized better and is thus preferable in performance-sensitive code.
///
- /// Compared to [`sub`], this method basically delays the requirement of staying
- /// within the same allocated object: [`sub`] is immediate Undefined Behavior when
- /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
- /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
- /// better and is thus preferable in performance-sensitive code.
+ /// The delayed check only considers the value of the pointer that was dereferenced, not the
+ /// intermediate values used during the computation of the final result. For example,
+ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
+ /// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`ptr::read`]: crate::ptr::read()
#[stable(feature = "pointer_methods", since = "1.26.0")]
+ #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
#[inline]
- pub unsafe fn read(self) -> T
+ pub const unsafe fn read(self) -> T
where
T: Sized,
{
///
/// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
#[stable(feature = "pointer_methods", since = "1.26.0")]
+ #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
#[inline]
- pub unsafe fn read_unaligned(self) -> T
+ pub const unsafe fn read_unaligned(self) -> T
where
T: Sized,
{
}
}
-// Use an equal-pointer optimization when types are `Eq`
-// We can't make `A` and `B` the same type because `min_specialization` won't
-// allow it.
-impl<A, B> SlicePartialEq<B> for [A]
-where
- A: MarkerEq<B>,
-{
- default fn equal(&self, other: &[B]) -> bool {
- if self.len() != other.len() {
- return false;
- }
-
- // While performance would suffer if `guaranteed_eq` just returned `false`
- // for all arguments, correctness and return value of this function are not affected.
- if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
- return true;
- }
-
- self.iter().zip(other.iter()).all(|(x, y)| x == y)
- }
-}
-
// Use memcmp for bytewise equality when the types allow
impl<A, B> SlicePartialEq<B> for [A]
where
return false;
}
- // While performance would suffer if `guaranteed_eq` just returned `false`
- // for all arguments, correctness and return value of this function are not affected.
- if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
- return true;
- }
// SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
// The two slices have been checked to have the same size above.
unsafe {
/// let a = [1, 2, 3];
/// assert_eq!(a.len(), 3);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(slice_fill)]
- ///
/// let mut buf = vec![0; 10];
/// buf.fill(1);
/// assert_eq!(buf, vec![1; 10]);
/// ```
#[doc(alias = "memset")]
- #[unstable(feature = "slice_fill", issue = "70758")]
+ #[stable(feature = "slice_fill", since = "1.50.0")]
pub fn fill(&mut self, value: T)
where
T: Clone,
/// assert_eq!("Æ’oo".len(), 4); // fancy f!
/// assert_eq!("Æ’oo".chars().count(), 3);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_len", since = "1.32.0")]
#[inline]
/// **Note:** This method is only available on platforms that support atomic
/// operations on `u8`.
///
+ /// # Migrating to `compare_exchange` and `compare_exchange_weak`
+ ///
+ /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for
+ /// memory orderings:
+ ///
+ /// Original | Success | Failure
+ /// -------- | ------- | -------
+ /// Relaxed | Relaxed | Relaxed
+ /// Acquire | Acquire | Acquire
+ /// Release | Release | Relaxed
+ /// AcqRel | AcqRel | Acquire
+ /// SeqCst | SeqCst | SeqCst
+ ///
+ /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
+ /// which allows the compiler to generate better assembly code when the compare and swap
+ /// is used in a loop.
+ ///
/// # Examples
///
/// ```
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(
+ since = "1.50.0",
+ reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+ )]
#[cfg(target_has_atomic = "8")]
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
/// the previous value. On success this value is guaranteed to be equal to `current`.
///
/// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
- /// ordering of this operation. The first describes the required ordering if the
- /// operation succeeds while the second describes the required ordering when the
- /// operation fails. Using [`Acquire`] as success ordering makes the store part
+ /// ordering of this operation. `success` describes the required ordering for the
+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+ /// `failure` describes the required ordering for the load operation that takes place when
+ /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+ #[doc(alias = "compare_and_swap")]
#[cfg(target_has_atomic = "8")]
pub fn compare_exchange(
&self,
/// previous value.
///
/// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
- /// ordering of this operation. The first describes the required ordering if the
- /// operation succeeds while the second describes the required ordering when the
- /// operation fails. Using [`Acquire`] as success ordering makes the store part
+ /// ordering of this operation. `success` describes the required ordering for the
+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+ /// `failure` describes the required ordering for the load operation that takes place when
+ /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+ #[doc(alias = "compare_and_swap")]
#[cfg(target_has_atomic = "8")]
pub fn compare_exchange_weak(
&self,
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn load(&self, order: Ordering) -> *mut T {
- #[cfg(not(bootstrap))]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_load(self.p.get(), order)
- }
- #[cfg(bootstrap)]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_load(self.p.get() as *mut usize, order) as *mut T
- }
+ unsafe { atomic_load(self.p.get(), order) }
}
/// Stores a value into the pointer.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn store(&self, ptr: *mut T, order: Ordering) {
- #[cfg(not(bootstrap))]
// SAFETY: data races are prevented by atomic intrinsics.
unsafe {
atomic_store(self.p.get(), ptr, order);
}
- #[cfg(bootstrap)]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_store(self.p.get() as *mut usize, ptr as usize, order);
- }
}
/// Stores a value into the pointer, returning the previous value.
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(target_has_atomic = "ptr")]
pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
- #[cfg(bootstrap)]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T
- }
- #[cfg(not(bootstrap))]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_swap(self.p.get(), ptr, order)
- }
+ unsafe { atomic_swap(self.p.get(), ptr, order) }
}
/// Stores a value into the pointer if the current value is the same as the `current` value.
/// **Note:** This method is only available on platforms that support atomic
/// operations on pointers.
///
+ /// # Migrating to `compare_exchange` and `compare_exchange_weak`
+ ///
+ /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for
+ /// memory orderings:
+ ///
+ /// Original | Success | Failure
+ /// -------- | ------- | -------
+ /// Relaxed | Relaxed | Relaxed
+ /// Acquire | Acquire | Acquire
+ /// Release | Release | Relaxed
+ /// AcqRel | AcqRel | Acquire
+ /// SeqCst | SeqCst | SeqCst
+ ///
+ /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
+ /// which allows the compiler to generate better assembly code when the compare and swap
+ /// is used in a loop.
+ ///
/// # Examples
///
/// ```
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(
+ since = "1.50.0",
+ reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+ )]
#[cfg(target_has_atomic = "ptr")]
pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
/// the previous value. On success this value is guaranteed to be equal to `current`.
///
/// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
- /// ordering of this operation. The first describes the required ordering if the
- /// operation succeeds while the second describes the required ordering when the
- /// operation fails. Using [`Acquire`] as success ordering makes the store part
+ /// ordering of this operation. `success` describes the required ordering for the
+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+ /// `failure` describes the required ordering for the load operation that takes place when
+ /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
success: Ordering,
failure: Ordering,
) -> Result<*mut T, *mut T> {
- #[cfg(bootstrap)]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- let res = atomic_compare_exchange(
- self.p.get() as *mut usize,
- current as usize,
- new as usize,
- success,
- failure,
- );
- match res {
- Ok(x) => Ok(x as *mut T),
- Err(x) => Err(x as *mut T),
- }
- }
- #[cfg(not(bootstrap))]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_compare_exchange(self.p.get(), current, new, success, failure)
- }
+ unsafe { atomic_compare_exchange(self.p.get(), current, new, success, failure) }
}
/// Stores a value into the pointer if the current value is the same as the `current` value.
/// previous value.
///
/// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
- /// ordering of this operation. The first describes the required ordering if the
- /// operation succeeds while the second describes the required ordering when the
- /// operation fails. Using [`Acquire`] as success ordering makes the store part
+ /// ordering of this operation. `success` describes the required ordering for the
+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+ /// `failure` describes the required ordering for the load operation that takes place when
+ /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
success: Ordering,
failure: Ordering,
) -> Result<*mut T, *mut T> {
- #[cfg(bootstrap)]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- let res = atomic_compare_exchange_weak(
- self.p.get() as *mut usize,
- current as usize,
- new as usize,
- success,
- failure,
- );
- match res {
- Ok(x) => Ok(x as *mut T),
- Err(x) => Err(x as *mut T),
- }
- }
- #[cfg(not(bootstrap))]
// SAFETY: This intrinsic is unsafe because it operates on a raw pointer
// but we know for sure that the pointer is valid (we just got it from
// an `UnsafeCell` that we have by reference) and the atomic operation
// itself allows us to safely mutate the `UnsafeCell` contents.
- unsafe {
- atomic_compare_exchange_weak(self.p.get(), current, new, success, failure)
- }
+ unsafe { atomic_compare_exchange_weak(self.p.get(), current, new, success, failure) }
}
/// Fetches the value, and applies a function to it that returns an optional
#[$stable_from]
impl From<$int_type> for $atomic_type {
- doc_comment! {
- concat!(
-"Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`."),
- #[inline]
- fn from(v: $int_type) -> Self { Self::new(v) }
- }
+ #[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")]
+ #[inline]
+ fn from(v: $int_type) -> Self { Self::new(v) }
}
#[$stable_debug]
unsafe impl Sync for $atomic_type {}
impl $atomic_type {
- doc_comment! {
- concat!("Creates a new atomic integer.
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
-
-let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
-```"),
- #[inline]
- #[$stable]
- #[$const_stable]
- pub const fn new(v: $int_type) -> Self {
- Self {v: UnsafeCell::new(v)}
- }
+ /// Creates a new atomic integer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";")]
+ ///
+ #[doc = concat!("let atomic_forty_two = ", stringify!($atomic_type), "::new(42);")]
+ /// ```
+ #[inline]
+ #[$stable]
+ #[$const_stable]
+ pub const fn new(v: $int_type) -> Self {
+ Self {v: UnsafeCell::new(v)}
}
- doc_comment! {
- concat!("Returns a mutable reference to the underlying integer.
-
-This is safe because the mutable reference guarantees that no other threads are
-concurrently accessing the atomic data.
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let mut some_var = ", stringify!($atomic_type), "::new(10);
-assert_eq!(*some_var.get_mut(), 10);
-*some_var.get_mut() = 5;
-assert_eq!(some_var.load(Ordering::SeqCst), 5);
-```"),
- #[inline]
- #[$stable_access]
- pub fn get_mut(&mut self) -> &mut $int_type {
- self.v.get_mut()
- }
+ /// Returns a mutable reference to the underlying integer.
+ ///
+ /// This is safe because the mutable reference guarantees that no other threads are
+ /// concurrently accessing the atomic data.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let mut some_var = ", stringify!($atomic_type), "::new(10);")]
+ /// assert_eq!(*some_var.get_mut(), 10);
+ /// *some_var.get_mut() = 5;
+ /// assert_eq!(some_var.load(Ordering::SeqCst), 5);
+ /// ```
+ #[inline]
+ #[$stable_access]
+ pub fn get_mut(&mut self) -> &mut $int_type {
+ self.v.get_mut()
}
- doc_comment! {
- concat!("Get atomic access to a `&mut ", stringify!($int_type), "`.
-
-",
-if_not_8_bit! {
- $int_type,
- concat!(
- "**Note:** This function is only available on targets where `",
- stringify!($int_type), "` has an alignment of ", $align, " bytes."
- )
-},
-"
-
-# Examples
-
-```
-#![feature(atomic_from_mut)]
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let mut some_int = 123;
-let a = ", stringify!($atomic_type), "::from_mut(&mut some_int);
-a.store(100, Ordering::Relaxed);
-assert_eq!(some_int, 100);
-```
- "),
- #[inline]
- #[$cfg_align]
- #[unstable(feature = "atomic_from_mut", issue = "76314")]
- pub fn from_mut(v: &mut $int_type) -> &Self {
- use crate::mem::align_of;
- let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
- // SAFETY:
- // - the mutable reference guarantees unique ownership.
- // - the alignment of `$int_type` and `Self` is the
- // same, as promised by $cfg_align and verified above.
- unsafe { &*(v as *mut $int_type as *mut Self) }
- }
+ #[doc = concat!("Get atomic access to a `&mut ", stringify!($int_type), "`.")]
+ ///
+ #[doc = if_not_8_bit! {
+ $int_type,
+ concat!(
+ "**Note:** This function is only available on targets where `",
+ stringify!($int_type), "` has an alignment of ", $align, " bytes."
+ )
+ }]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(atomic_from_mut)]
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ /// let mut some_int = 123;
+ #[doc = concat!("let a = ", stringify!($atomic_type), "::from_mut(&mut some_int);")]
+ /// a.store(100, Ordering::Relaxed);
+ /// assert_eq!(some_int, 100);
+ /// ```
+ ///
+ #[inline]
+ #[$cfg_align]
+ #[unstable(feature = "atomic_from_mut", issue = "76314")]
+ pub fn from_mut(v: &mut $int_type) -> &Self {
+ use crate::mem::align_of;
+ let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
+ // SAFETY:
+ // - the mutable reference guarantees unique ownership.
+ // - the alignment of `$int_type` and `Self` is the
+ // same, as promised by $cfg_align and verified above.
+ unsafe { &*(v as *mut $int_type as *mut Self) }
}
- doc_comment! {
- concat!("Consumes the atomic and returns the contained value.
-
-This is safe because passing `self` by value guarantees that no other threads are
-concurrently accessing the atomic data.
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-assert_eq!(some_var.into_inner(), 5);
-```"),
- #[inline]
- #[$stable_access]
- #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
- pub const fn into_inner(self) -> $int_type {
- self.v.into_inner()
- }
+ /// Consumes the atomic and returns the contained value.
+ ///
+ /// This is safe because passing `self` by value guarantees that no other threads are
+ /// concurrently accessing the atomic data.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";")]
+ ///
+ #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+ /// assert_eq!(some_var.into_inner(), 5);
+ /// ```
+ #[inline]
+ #[$stable_access]
+ #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+ pub const fn into_inner(self) -> $int_type {
+ self.v.into_inner()
}
- doc_comment! {
- concat!("Loads a value from the atomic integer.
-
-`load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
-Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
-
-# Panics
-
-Panics if `order` is [`Release`] or [`AcqRel`].
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.load(Ordering::Relaxed), 5);
-```"),
- #[inline]
- #[$stable]
- pub fn load(&self, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_load(self.v.get(), order) }
- }
+ /// Loads a value from the atomic integer.
+ ///
+ /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
+ /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `order` is [`Release`] or [`AcqRel`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+ ///
+ /// assert_eq!(some_var.load(Ordering::Relaxed), 5);
+ /// ```
+ #[inline]
+ #[$stable]
+ pub fn load(&self, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_load(self.v.get(), order) }
}
- doc_comment! {
- concat!("Stores a value into the atomic integer.
-
-`store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
- Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
-
-# Panics
-
-Panics if `order` is [`Acquire`] or [`AcqRel`].
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-some_var.store(10, Ordering::Relaxed);
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-```"),
- #[inline]
- #[$stable]
- pub fn store(&self, val: $int_type, order: Ordering) {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_store(self.v.get(), val, order); }
- }
+ /// Stores a value into the atomic integer.
+ ///
+ /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
+ /// Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `order` is [`Acquire`] or [`AcqRel`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+ ///
+ /// some_var.store(10, Ordering::Relaxed);
+ /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+ /// ```
+ #[inline]
+ #[$stable]
+ pub fn store(&self, val: $int_type, order: Ordering) {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_store(self.v.get(), val, order); }
}
- doc_comment! {
- concat!("Stores a value into the atomic integer, returning the previous value.
-
-`swap` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
-```"),
- #[inline]
- #[$stable]
- #[$cfg_cas]
- pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_swap(self.v.get(), val, order) }
- }
+ /// Stores a value into the atomic integer, returning the previous value.
+ ///
+ /// `swap` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+ ///
+ /// assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
+ /// ```
+ #[inline]
+ #[$stable]
+ #[$cfg_cas]
+ pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_swap(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Stores a value into the atomic integer if the current value is the same as
-the `current` value.
-
-The return value is always the previous value. If it is equal to `current`, then the
-value was updated.
-
-`compare_and_swap` also takes an [`Ordering`] argument which describes the memory
-ordering of this operation. Notice that even when using [`AcqRel`], the operation
-might fail and hence just perform an `Acquire` load, but not have `Release` semantics.
-Using [`Acquire`] makes the store part of this operation [`Relaxed`] if it
-happens, and using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.compare_and_swap(5, 10, Ordering::Relaxed), 5);
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-
-assert_eq!(some_var.compare_and_swap(6, 12, Ordering::Relaxed), 10);
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-```"),
- #[inline]
- #[$stable]
- #[$cfg_cas]
- pub fn compare_and_swap(&self,
- current: $int_type,
- new: $int_type,
- order: Ordering) -> $int_type {
- match self.compare_exchange(current,
- new,
- order,
- strongest_failure_ordering(order)) {
- Ok(x) => x,
- Err(x) => x,
- }
+ /// Stores a value into the atomic integer if the current value is the same as
+ /// the `current` value.
+ ///
+ /// The return value is always the previous value. If it is equal to `current`, then the
+ /// value was updated.
+ ///
+ /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory
+ /// ordering of this operation. Notice that even when using [`AcqRel`], the operation
+ /// might fail and hence just perform an `Acquire` load, but not have `Release` semantics.
+ /// Using [`Acquire`] makes the store part of this operation [`Relaxed`] if it
+ /// happens, and using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Migrating to `compare_exchange` and `compare_exchange_weak`
+ ///
+ /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for
+ /// memory orderings:
+ ///
+ /// Original | Success | Failure
+ /// -------- | ------- | -------
+ /// Relaxed | Relaxed | Relaxed
+ /// Acquire | Acquire | Acquire
+ /// Release | Release | Relaxed
+ /// AcqRel | AcqRel | Acquire
+ /// SeqCst | SeqCst | SeqCst
+ ///
+ /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
+ /// which allows the compiler to generate better assembly code when the compare and swap
+ /// is used in a loop.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+ ///
+ /// assert_eq!(some_var.compare_and_swap(5, 10, Ordering::Relaxed), 5);
+ /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+ ///
+ /// assert_eq!(some_var.compare_and_swap(6, 12, Ordering::Relaxed), 10);
+ /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+ /// ```
+ #[inline]
+ #[$stable]
+ #[rustc_deprecated(
+ since = "1.50.0",
+ reason = "Use `compare_exchange` or `compare_exchange_weak` instead")
+ ]
+ #[$cfg_cas]
+ pub fn compare_and_swap(&self,
+ current: $int_type,
+ new: $int_type,
+ order: Ordering) -> $int_type {
+ match self.compare_exchange(current,
+ new,
+ order,
+ strongest_failure_ordering(order)) {
+ Ok(x) => x,
+ Err(x) => x,
}
}
- doc_comment! {
- concat!("Stores a value into the atomic integer if the current value is the same as
-the `current` value.
-
-The return value is a result indicating whether the new value was written and
-containing the previous value. On success this value is guaranteed to be equal to
-`current`.
-
-`compare_exchange` takes two [`Ordering`] arguments to describe the memory
-ordering of this operation. The first describes the required ordering if the
-operation succeeds while the second describes the required ordering when the
-operation fails. Using [`Acquire`] as success ordering makes the store part
-of this operation [`Relaxed`], and using [`Release`] makes the successful load
-[`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
-and must be equivalent to or weaker than the success ordering.
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let some_var = ", stringify!($atomic_type), "::new(5);
-
-assert_eq!(some_var.compare_exchange(5, 10,
- Ordering::Acquire,
- Ordering::Relaxed),
- Ok(5));
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-
-assert_eq!(some_var.compare_exchange(6, 12,
- Ordering::SeqCst,
- Ordering::Acquire),
- Err(10));
-assert_eq!(some_var.load(Ordering::Relaxed), 10);
-```"),
- #[inline]
- #[$stable_cxchg]
- #[$cfg_cas]
- pub fn compare_exchange(&self,
- current: $int_type,
- new: $int_type,
- success: Ordering,
- failure: Ordering) -> Result<$int_type, $int_type> {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
- }
+ /// Stores a value into the atomic integer if the current value is the same as
+ /// the `current` value.
+ ///
+ /// The return value is a result indicating whether the new value was written and
+ /// containing the previous value. On success this value is guaranteed to be equal to
+ /// `current`.
+ ///
+ /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
+ /// ordering of this operation. `success` describes the required ordering for the
+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+ /// `failure` describes the required ordering for the load operation that takes place when
+ /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
+ /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
+ /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
+ /// and must be equivalent to or weaker than the success ordering.
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let some_var = ", stringify!($atomic_type), "::new(5);")]
+ ///
+ /// assert_eq!(some_var.compare_exchange(5, 10,
+ /// Ordering::Acquire,
+ /// Ordering::Relaxed),
+ /// Ok(5));
+ /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+ ///
+ /// assert_eq!(some_var.compare_exchange(6, 12,
+ /// Ordering::SeqCst,
+ /// Ordering::Acquire),
+ /// Err(10));
+ /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
+ /// ```
+ #[inline]
+ #[$stable_cxchg]
+ #[$cfg_cas]
+ pub fn compare_exchange(&self,
+ current: $int_type,
+ new: $int_type,
+ success: Ordering,
+ failure: Ordering) -> Result<$int_type, $int_type> {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
}
- doc_comment! {
- concat!("Stores a value into the atomic integer if the current value is the same as
-the `current` value.
-
-Unlike [`", stringify!($atomic_type), "::compare_exchange`], this function is allowed to spuriously fail even
-when the comparison succeeds, which can result in more efficient code on some
-platforms. The return value is a result indicating whether the new value was
-written and containing the previous value.
-
-`compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
-ordering of this operation. The first describes the required ordering if the
-operation succeeds while the second describes the required ordering when the
-operation fails. Using [`Acquire`] as success ordering makes the store part
-of this operation [`Relaxed`], and using [`Release`] makes the successful load
-[`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
-and must be equivalent to or weaker than the success ordering.
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let val = ", stringify!($atomic_type), "::new(4);
-
-let mut old = val.load(Ordering::Relaxed);
-loop {
- let new = old * 2;
- match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
- Ok(_) => break,
- Err(x) => old = x,
- }
-}
-```"),
- #[inline]
- #[$stable_cxchg]
- #[$cfg_cas]
- pub fn compare_exchange_weak(&self,
- current: $int_type,
- new: $int_type,
- success: Ordering,
- failure: Ordering) -> Result<$int_type, $int_type> {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
- }
+ /// Stores a value into the atomic integer if the current value is the same as
+ /// the `current` value.
+ ///
+ #[doc = concat!("Unlike [`", stringify!($atomic_type), "::compare_exchange`],")]
+ /// this function is allowed to spuriously fail even
+ /// when the comparison succeeds, which can result in more efficient code on some
+ /// platforms. The return value is a result indicating whether the new value was
+ /// written and containing the previous value.
+ ///
+ /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
+ /// ordering of this operation. `success` describes the required ordering for the
+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
+ /// `failure` describes the required ordering for the load operation that takes place when
+ /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
+ /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
+ /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
+ /// and must be equivalent to or weaker than the success ordering.
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let val = ", stringify!($atomic_type), "::new(4);")]
+ ///
+ /// let mut old = val.load(Ordering::Relaxed);
+ /// loop {
+ /// let new = old * 2;
+ /// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
+ /// Ok(_) => break,
+ /// Err(x) => old = x,
+ /// }
+ /// }
+ /// ```
+ #[inline]
+ #[$stable_cxchg]
+ #[$cfg_cas]
+ pub fn compare_exchange_weak(&self,
+ current: $int_type,
+ new: $int_type,
+ success: Ordering,
+ failure: Ordering) -> Result<$int_type, $int_type> {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe {
+ atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
}
}
- doc_comment! {
- concat!("Adds to the current value, returning the previous value.
-
-This operation wraps around on overflow.
-
-`fetch_add` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0);
-assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
-assert_eq!(foo.load(Ordering::SeqCst), 10);
-```"),
- #[inline]
- #[$stable]
- #[$cfg_cas]
- pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_add(self.v.get(), val, order) }
- }
+ /// Adds to the current value, returning the previous value.
+ ///
+ /// This operation wraps around on overflow.
+ ///
+ /// `fetch_add` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0);")]
+ /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 10);
+ /// ```
+ #[inline]
+ #[$stable]
+ #[$cfg_cas]
+ pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_add(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Subtracts from the current value, returning the previous value.
-
-This operation wraps around on overflow.
-
-`fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(20);
-assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20);
-assert_eq!(foo.load(Ordering::SeqCst), 10);
-```"),
- #[inline]
- #[$stable]
- #[$cfg_cas]
- pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_sub(self.v.get(), val, order) }
- }
+ /// Subtracts from the current value, returning the previous value.
+ ///
+ /// This operation wraps around on overflow.
+ ///
+ /// `fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(20);")]
+ /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 10);
+ /// ```
+ #[inline]
+ #[$stable]
+ #[$cfg_cas]
+ pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_sub(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Bitwise \"and\" with the current value.
-
-Performs a bitwise \"and\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_and` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0b101101);
-assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
-assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
-```"),
- #[inline]
- #[$stable]
- #[$cfg_cas]
- pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_and(self.v.get(), val, order) }
- }
+ /// Bitwise "and" with the current value.
+ ///
+ /// Performs a bitwise "and" operation on the current value and the argument `val`, and
+ /// sets the new value to the result.
+ ///
+ /// Returns the previous value.
+ ///
+ /// `fetch_and` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0b101101);")]
+ /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
+ /// ```
+ #[inline]
+ #[$stable]
+ #[$cfg_cas]
+ pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_and(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Bitwise \"nand\" with the current value.
-
-Performs a bitwise \"nand\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "
-use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0x13);
-assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13);
-assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
-```"),
- #[inline]
- #[$stable_nand]
- #[$cfg_cas]
- pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_nand(self.v.get(), val, order) }
- }
+ /// Bitwise "nand" with the current value.
+ ///
+ /// Performs a bitwise "nand" operation on the current value and the argument `val`, and
+ /// sets the new value to the result.
+ ///
+ /// Returns the previous value.
+ ///
+ /// `fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0x13);")]
+ /// assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13);
+ /// assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
+ /// ```
+ #[inline]
+ #[$stable_nand]
+ #[$cfg_cas]
+ pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_nand(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Bitwise \"or\" with the current value.
-
-Performs a bitwise \"or\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_or` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0b101101);
-assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
-assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
-```"),
- #[inline]
- #[$stable]
- #[$cfg_cas]
- pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_or(self.v.get(), val, order) }
- }
+ /// Bitwise "or" with the current value.
+ ///
+ /// Performs a bitwise "or" operation on the current value and the argument `val`, and
+ /// sets the new value to the result.
+ ///
+ /// Returns the previous value.
+ ///
+ /// `fetch_or` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0b101101);")]
+ /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
+ /// ```
+ #[inline]
+ #[$stable]
+ #[$cfg_cas]
+ pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_or(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Bitwise \"xor\" with the current value.
-
-Performs a bitwise \"xor\" operation on the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(0b101101);
-assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
-assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
-```"),
- #[inline]
- #[$stable]
- #[$cfg_cas]
- pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_xor(self.v.get(), val, order) }
- }
+ /// Bitwise "xor" with the current value.
+ ///
+ /// Performs a bitwise "xor" operation on the current value and the argument `val`, and
+ /// sets the new value to the result.
+ ///
+ /// Returns the previous value.
+ ///
+ /// `fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(0b101101);")]
+ /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
+ /// ```
+ #[inline]
+ #[$stable]
+ #[$cfg_cas]
+ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_xor(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Fetches the value, and applies a function to it that returns an optional
-new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
-`Err(previous_value)`.
-
-Note: This may call the function multiple times if the value has been changed from other threads in
-the meantime, as long as the function returns `Some(_)`, but the function will have been applied
-only once to the stored value.
-
-`fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
-The first describes the required ordering for when the operation finally succeeds while the second
-describes the required ordering for loads. These correspond to the success and failure orderings of
-[`", stringify!($atomic_type), "::compare_exchange`] respectively.
-
-Using [`Acquire`] as success ordering makes the store part
-of this operation [`Relaxed`], and using [`Release`] makes the final successful load
-[`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
-and must be equivalent to or weaker than the success ordering.
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```rust
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let x = ", stringify!($atomic_type), "::new(7);
-assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
-assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
-assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
-assert_eq!(x.load(Ordering::SeqCst), 9);
-```"),
- #[inline]
- #[stable(feature = "no_more_cas", since = "1.45.0")]
- #[$cfg_cas]
- pub fn fetch_update<F>(&self,
- set_order: Ordering,
- fetch_order: Ordering,
- mut f: F) -> Result<$int_type, $int_type>
- where F: FnMut($int_type) -> Option<$int_type> {
- let mut prev = self.load(fetch_order);
- while let Some(next) = f(prev) {
- match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
- x @ Ok(_) => return x,
- Err(next_prev) => prev = next_prev
- }
+ /// Fetches the value, and applies a function to it that returns an optional
+ /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
+ /// `Err(previous_value)`.
+ ///
+ /// Note: This may call the function multiple times if the value has been changed from other threads in
+ /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
+ /// only once to the stored value.
+ ///
+ /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
+ /// The first describes the required ordering for when the operation finally succeeds while the second
+ /// describes the required ordering for loads. These correspond to the success and failure orderings of
+ #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")]
+ /// respectively.
+ ///
+ /// Using [`Acquire`] as success ordering makes the store part
+ /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
+ /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
+ /// and must be equivalent to or weaker than the success ordering.
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")]
+ /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
+ /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
+ /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
+ /// assert_eq!(x.load(Ordering::SeqCst), 9);
+ /// ```
+ #[inline]
+ #[stable(feature = "no_more_cas", since = "1.45.0")]
+ #[$cfg_cas]
+ pub fn fetch_update<F>(&self,
+ set_order: Ordering,
+ fetch_order: Ordering,
+ mut f: F) -> Result<$int_type, $int_type>
+ where F: FnMut($int_type) -> Option<$int_type> {
+ let mut prev = self.load(fetch_order);
+ while let Some(next) = f(prev) {
+ match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
+ x @ Ok(_) => return x,
+ Err(next_prev) => prev = next_prev
}
- Err(prev)
}
+ Err(prev)
}
- doc_comment! {
- concat!("Maximum with the current value.
-
-Finds the maximum of the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_max` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
-assert_eq!(foo.load(Ordering::SeqCst), 42);
-```
-
-If you want to obtain the maximum value in one step, you can use the following:
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-let bar = 42;
-let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
-assert!(max_foo == 42);
-```"),
- #[inline]
- #[stable(feature = "atomic_min_max", since = "1.45.0")]
- #[$cfg_cas]
- pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { $max_fn(self.v.get(), val, order) }
- }
+ /// Maximum with the current value.
+ ///
+ /// Finds the maximum of the current value and the argument `val`, and
+ /// sets the new value to the result.
+ ///
+ /// Returns the previous value.
+ ///
+ /// `fetch_max` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+ /// assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 42);
+ /// ```
+ ///
+ /// If you want to obtain the maximum value in one step, you can use the following:
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+ /// let bar = 42;
+ /// let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
+ /// assert!(max_foo == 42);
+ /// ```
+ #[inline]
+ #[stable(feature = "atomic_min_max", since = "1.45.0")]
+ #[$cfg_cas]
+ pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { $max_fn(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Minimum with the current value.
-
-Finds the minimum of the current value and the argument `val`, and
-sets the new value to the result.
-
-Returns the previous value.
-
-`fetch_min` takes an [`Ordering`] argument which describes the memory ordering
-of this operation. All ordering modes are possible. Note that using
-[`Acquire`] makes the store part of this operation [`Relaxed`], and
-using [`Release`] makes the load part [`Relaxed`].
-
-**Note**: This method is only available on platforms that support atomic
-operations on [`", $s_int_type, "`](", $int_ref, ").
-
-# Examples
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
-assert_eq!(foo.load(Ordering::Relaxed), 23);
-assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
-assert_eq!(foo.load(Ordering::Relaxed), 22);
-```
-
-If you want to obtain the minimum value in one step, you can use the following:
-
-```
-", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
-
-let foo = ", stringify!($atomic_type), "::new(23);
-let bar = 12;
-let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
-assert_eq!(min_foo, 12);
-```"),
- #[inline]
- #[stable(feature = "atomic_min_max", since = "1.45.0")]
- #[$cfg_cas]
- pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { $min_fn(self.v.get(), val, order) }
- }
+ /// Minimum with the current value.
+ ///
+ /// Finds the minimum of the current value and the argument `val`, and
+ /// sets the new value to the result.
+ ///
+ /// Returns the previous value.
+ ///
+ /// `fetch_min` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation. All ordering modes are possible. Note that using
+ /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+ /// using [`Release`] makes the load part [`Relaxed`].
+ ///
+ /// **Note**: This method is only available on platforms that support atomic operations on
+ #[doc = concat!("[`", $s_int_type, "`](", $int_ref, ").")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+ /// assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
+ /// assert_eq!(foo.load(Ordering::Relaxed), 23);
+ /// assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
+ /// assert_eq!(foo.load(Ordering::Relaxed), 22);
+ /// ```
+ ///
+ /// If you want to obtain the minimum value in one step, you can use the following:
+ ///
+ /// ```
+ #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+ ///
+ #[doc = concat!("let foo = ", stringify!($atomic_type), "::new(23);")]
+ /// let bar = 12;
+ /// let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
+ /// assert_eq!(min_foo, 12);
+ /// ```
+ #[inline]
+ #[stable(feature = "atomic_min_max", since = "1.45.0")]
+ #[$cfg_cas]
+ pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { $min_fn(self.v.get(), val, order) }
}
- doc_comment! {
- concat!("Returns a mutable pointer to the underlying integer.
-
-Doing non-atomic reads and writes on the resulting integer can be a data race.
-This method is mostly useful for FFI, where the function signature may use
-`*mut ", stringify!($int_type), "` instead of `&", stringify!($atomic_type), "`.
-
-Returning an `*mut` pointer from a shared reference to this atomic is safe because the
-atomic types work with interior mutability. All modifications of an atomic change the value
-through a shared reference, and can do so safely as long as they use atomic operations. Any
-use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
-restriction: operations on it must be atomic.
-
-# Examples
-
-```ignore (extern-declaration)
-# fn main() {
-", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";
-
-extern {
- fn my_atomic_op(arg: *mut ", stringify!($int_type), ");
-}
-
-let mut atomic = ", stringify!($atomic_type), "::new(1);
-",
-// SAFETY: Safe as long as `my_atomic_op` is atomic.
-"unsafe {
- my_atomic_op(atomic.as_mut_ptr());
-}
-# }
-```"),
- #[inline]
- #[unstable(feature = "atomic_mut_ptr",
- reason = "recently added",
- issue = "66893")]
- pub fn as_mut_ptr(&self) -> *mut $int_type {
- self.v.get()
- }
+ /// Returns a mutable pointer to the underlying integer.
+ ///
+ /// Doing non-atomic reads and writes on the resulting integer can be a data race.
+ /// This method is mostly useful for FFI, where the function signature may use
+ #[doc = concat!("`*mut ", stringify!($int_type), "` instead of `&", stringify!($atomic_type), "`.")]
+ ///
+ /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
+ /// atomic types work with interior mutability. All modifications of an atomic change the value
+ /// through a shared reference, and can do so safely as long as they use atomic operations. Any
+ /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
+ /// restriction: operations on it must be atomic.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore (extern-declaration)
+ /// # fn main() {
+ #[doc = concat!($extra_feature, "use std::sync::atomic::", stringify!($atomic_type), ";")]
+ ///
+ /// extern {
+ #[doc = concat!(" fn my_atomic_op(arg: *mut ", stringify!($int_type), ");")]
+ /// }
+ ///
+ #[doc = concat!("let mut atomic = ", stringify!($atomic_type), "::new(1);")]
+ ///
+ // SAFETY: Safe as long as `my_atomic_op` is atomic.
+ /// unsafe {
+ /// my_atomic_op(atomic.as_mut_ptr());
+ /// }
+ /// # }
+ /// ```
+ #[inline]
+ #[unstable(feature = "atomic_mut_ptr",
+ reason = "recently added",
+ issue = "66893")]
+ pub fn as_mut_ptr(&self) -> *mut $int_type {
+ self.v.get()
}
}
}
#[test]
fn bool_() {
let a = AtomicBool::new(false);
- assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
- assert_eq!(a.compare_and_swap(false, true, SeqCst), true);
+ assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false));
+ assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Err(true));
a.store(false, SeqCst);
- assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
+ assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false));
}
#[test]
--- /dev/null
+// Aligned to two bytes
+const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])];
+
+const fn unaligned_ptr() -> *const u16 {
+ // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16
+ unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 }
+}
+
+#[test]
+fn read() {
+ use core::ptr;
+
+ const FOO: i32 = unsafe { ptr::read(&42 as *const i32) };
+ assert_eq!(FOO, 42);
+
+ const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) };
+ assert_eq!(ALIGNED, 42);
+
+ const UNALIGNED_PTR: *const u16 = unaligned_ptr();
+
+ const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) };
+ assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
+
+#[test]
+fn const_ptr_read() {
+ const FOO: i32 = unsafe { (&42 as *const i32).read() };
+ assert_eq!(FOO, 42);
+
+ const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() };
+ assert_eq!(ALIGNED, 42);
+
+ const UNALIGNED_PTR: *const u16 = unaligned_ptr();
+
+ const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
+ assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
+
+#[test]
+fn mut_ptr_read() {
+ const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() };
+ assert_eq!(FOO, 42);
+
+ const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() };
+ assert_eq!(ALIGNED, 42);
+
+ const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16;
+
+ const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
+ assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
}
assert_eq!(x, 5);
}
+
+#[test]
+fn test_intersperse() {
+ let xs = ["a", "", "b", "c"];
+ let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
+ let text: String = v.concat();
+ assert_eq!(text, "a, , b, c".to_string());
+
+ let ys = [0, 1, 2, 3];
+ let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
+ assert!(it.next() == None);
+}
+
+#[test]
+fn test_intersperse_size_hint() {
+ let xs = ["a", "", "b", "c"];
+ let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
+ assert_eq!(iter.size_hint(), (7, Some(7)));
+
+ assert_eq!(iter.next(), Some("a"));
+ assert_eq!(iter.size_hint(), (6, Some(6)));
+ assert_eq!(iter.next(), Some(", "));
+ assert_eq!(iter.size_hint(), (5, Some(5)));
+
+ assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0)));
+}
+
+#[test]
+fn test_fold_specialization_intersperse() {
+ let mut iter = (1..2).intersperse(0);
+ iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+ let mut iter = (1..3).intersperse(0);
+ iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+ let mut iter = (1..4).intersperse(0);
+ iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_ok() {
+ let mut iter = (1..2).intersperse(0);
+ iter.clone().try_for_each(|x| {
+ assert_eq!(Some(x), iter.next());
+ Some(())
+ });
+
+ let mut iter = (1..3).intersperse(0);
+ iter.clone().try_for_each(|x| {
+ assert_eq!(Some(x), iter.next());
+ Some(())
+ });
+
+ let mut iter = (1..4).intersperse(0);
+ iter.clone().try_for_each(|x| {
+ assert_eq!(Some(x), iter.next());
+ Some(())
+ });
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_err() {
+ let orig_iter = ["a", "b"].iter().copied().intersperse("-");
+
+ // Abort after the first item.
+ let mut iter = orig_iter.clone();
+ iter.try_for_each(|_| None::<()>);
+ assert_eq!(iter.next(), Some("-"));
+ assert_eq!(iter.next(), Some("b"));
+ assert_eq!(iter.next(), None);
+
+ // Abort after the second item.
+ let mut iter = orig_iter.clone();
+ iter.try_for_each(|item| if item == "-" { None } else { Some(()) });
+ assert_eq!(iter.next(), Some("b"));
+ assert_eq!(iter.next(), None);
+
+ // Abort after the third item.
+ let mut iter = orig_iter.clone();
+ iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
+ assert_eq!(iter.next(), None);
+}
#![feature(const_assume)]
#![feature(const_cell_into_inner)]
#![feature(const_maybe_uninit_assume_init)]
+#![feature(const_ptr_read)]
+#![feature(const_ptr_offset)]
#![feature(core_intrinsics)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(raw)]
#![feature(sort_internals)]
#![feature(slice_partition_at_index)]
+#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)]
#![feature(step_trait)]
#![feature(array_value_iter)]
#![feature(iter_advance_by)]
#![feature(iter_partition_in_place)]
+#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]
#![feature(cmp_min_max_by)]
mod char;
mod clone;
mod cmp;
+
+#[cfg(not(bootstrap))]
+mod const_ptr;
+
mod fmt;
mod hash;
mod intrinsics;
}
#[test]
-#[cfg(not(bootstrap))]
fn assume_init_good() {
const TRUE: bool = unsafe { MaybeUninit::<bool>::new(true).assume_init() };
forget(src);
}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn uninit_const_assume_init_read() {
+ const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
+ assert_eq!(FOO, 42);
+}
const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
assert_eq!(TRAILING_ZEROS, 2);
}
+
+#[test]
+fn test_nonzero_uint_div() {
+ let nz = NonZeroU32::new(1).unwrap();
+
+ let x: u32 = 42u32 / nz;
+ assert_eq!(x, 42u32);
+}
+
+#[test]
+fn test_nonzero_uint_rem() {
+ let nz = NonZeroU32::new(10).unwrap();
+
+ let x: u32 = 42u32 % nz;
+ assert_eq!(x, 2u32);
+}
#![feature(core_intrinsics)]
#![feature(nll)]
#![feature(panic_runtime)]
+#![feature(std_internals)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![feature(asm)]
use core::any::Any;
+use core::panic::BoxMeUp;
#[rustc_std_internal_symbol]
#[allow(improper_ctypes_definitions)]
// "Leak" the payload and shim to the relevant abort on the platform in question.
#[rustc_std_internal_symbol]
-pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
+pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
abort();
cfg_if::cfg_if! {
// implementation.
#[rustc_std_internal_symbol]
#[unwind(allowed)]
-pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
- let payload = payload as *mut &mut dyn BoxMeUp;
- let payload = (*payload).take_box();
+pub unsafe extern "C" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
+ let payload = Box::from_raw((*payload).take_box());
- imp::panic(Box::from_raw(payload))
+ imp::panic(payload)
}
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(negative_impls)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
#![feature(no_core)]
#![feature(lang_items)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![crate_type = "rlib"]
#![no_core]
#![allow(non_camel_case_types)]
#![feature(no_core)]
#![feature(lang_items)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![crate_type = "rlib"]
#![no_core]
reexports all of its contents. The crate is the crux of empowering the standard
library to depend on crates from crates.io
-Crates on crates.io that the standard library depend on the
-`rustc-std-workspace-core` crate from crates.io. On crates.io, however, this
-crate is empty. We use `[patch]` to override it to this crate in this
-repository. As a result, crates on crates.io will draw a dependency edge to
-`libcore`, the version defined in this repository. That should draw all the
-dependency edges to ensure Cargo builds crates successfully!
+Crates on crates.io that the standard library depend on need to depend on the
+`rustc-std-workspace-core` crate from crates.io, which is empty. We use
+`[patch]` to override it to this crate in this repository. As a result, crates
+on crates.io will draw a dependency edge to `libcore`, the version defined in
+this repository. That should draw all the dependency edges to ensure Cargo
+builds crates successfully!
Note that crates on crates.io need to depend on this crate with the name `core`
for everything to work correctly. To do that they can use:
/// // use the values stored in map
/// ```
-#[derive(Clone)]
#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct HashMap<K, V, S = RandomState> {
/// a.insert(1, "a");
/// assert_eq!(a.len(), 1);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.base.len()
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<K, V, S> Clone for HashMap<K, V, S>
+where
+ K: Clone,
+ V: Clone,
+ S: Clone,
+{
+ #[inline]
+ fn clone(&self) -> Self {
+ Self { base: self.base.clone() }
+ }
+
+ #[inline]
+ fn clone_from(&mut self, other: &Self) {
+ self.base.clone_from(&other.base);
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> PartialEq for HashMap<K, V, S>
where
/// [`HashMap`]: crate::collections::HashMap
/// [`RefCell`]: crate::cell::RefCell
/// [`Cell`]: crate::cell::Cell
-#[derive(Clone)]
#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct HashSet<T, S = RandomState> {
/// v.insert(1);
/// assert_eq!(v.len(), 1);
/// ```
+ #[doc(alias = "length")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, S> Clone for HashSet<T, S>
+where
+ T: Clone,
+ S: Clone,
+{
+ #[inline]
+ fn clone(&self) -> Self {
+ Self { base: self.base.clone() }
+ }
+
+ #[inline]
+ fn clone_from(&mut self, other: &Self) {
+ self.base.clone_from(&other.base);
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> PartialEq for HashSet<T, S>
where
/// let os_str = OsStr::new("foo");
/// assert_eq!(os_str.len(), 3);
/// ```
+ #[doc(alias = "length")]
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn len(&self) -> usize {
self.inner.inner.len()
//! [`str`]: prim@str
//! [`mpsc`]: sync::mpsc
//! [`std::cmp`]: cmp
-//! [`std::slice`]: slice
+//! [`std::slice`]: mod@slice
//! [`use std::env`]: env/index.html
//! [`use`]: ../book/ch07-02-defining-modules-to-control-scope-and-privacy.html
//! [crates.io]: https://crates.io
//! [other]: #what-is-in-the-standard-library-documentation
//! [primitive types]: ../book/ch03-02-data-types.html
//! [rust-discord]: https://discord.gg/rust-lang
-
+#![cfg_attr(not(bootstrap), doc = "[array]: prim@array")]
+#![cfg_attr(not(bootstrap), doc = "[slice]: prim@slice")]
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![feature(or_patterns)]
#![feature(panic_info_message)]
#![feature(panic_internals)]
#![feature(rustc_private)]
#![feature(shrink_to)]
#![feature(slice_concat_ext)]
-#![feature(slice_fill)]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(libstd_sys_internals)]
-#[cfg_attr(not(any(bootstrap, test)), rustc_diagnostic_item = "std_panic_macro")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")]
macro_rules! panic {
() => ({ $crate::panic!("explicit panic") });
($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) });
extern "C" {
fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);
- /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings.
- /// It cannot be `Box<dyn BoxMeUp>` because the other end of this call does not depend
- /// on liballoc, and thus cannot use `Box`.
+ /// `payload` is passed through another layer of raw pointers as `&mut dyn Trait` is not
+ /// FFI-safe. `BoxMeUp` lazily performs allocation only when needed (this avoids allocations
+ /// when using the "abort" panic runtime).
#[unwind(allowed)]
- fn __rust_start_panic(payload: usize) -> u32;
+ fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32;
}
/// This function is called by the panic runtime if FFI code catches a Rust
fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
let code = unsafe {
let obj = &mut msg as *mut &mut dyn BoxMeUp;
- __rust_start_panic(obj as usize)
+ __rust_start_panic(obj)
};
rtabort!("failed to initiate panic, error {}", code)
}
impl SignalToken {
pub fn signal(&self) -> bool {
- let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
+ let wake = self
+ .inner
+ .woken
+ .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
+ .is_ok();
if wake {
self.inner.thread.unpark();
}
let ptr = unsafe { signal_token.cast_to_usize() };
// race with senders to enter the blocking state
- if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY {
+ if self.state.compare_exchange(EMPTY, ptr, Ordering::SeqCst, Ordering::SeqCst).is_ok() {
if let Some(deadline) = deadline {
let timed_out = !wait_token.wait_max_until(deadline);
// Try to reset the state
// the state changes under our feet we'd rather just see that state
// change.
DATA => {
- self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst);
+ let _ = self.state.compare_exchange(
+ DATA,
+ EMPTY,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ );
match (&mut *self.data.get()).take() {
Some(data) => Ok(data),
None => unreachable!(),
// If we've got a blocked thread, then use an atomic to gain ownership
// of it (may fail)
- ptr => self.state.compare_and_swap(ptr, EMPTY, Ordering::SeqCst),
+ ptr => self
+ .state
+ .compare_exchange(ptr, EMPTY, Ordering::SeqCst, Ordering::SeqCst)
+ .unwrap_or_else(|x| x),
};
// Now that we've got ownership of our state, figure out what to do
self.port_dropped.store(true, Ordering::SeqCst);
let mut steals = unsafe { *self.steals.get() };
while {
- let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst);
- cnt != DISCONNECTED && cnt != steals
+ match self.cnt.compare_exchange(
+ steals,
+ DISCONNECTED,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ ) {
+ Ok(_) => false,
+ Err(old) => old != DISCONNECTED,
+ }
} {
// See the discussion in 'try_recv' for why we yield
// control of this thread.
// (because there is a bounded number of senders).
let mut steals = unsafe { *self.queue.consumer_addition().steals.get() };
while {
- let cnt = self.queue.producer_addition().cnt.compare_and_swap(
+ match self.queue.producer_addition().cnt.compare_exchange(
steals,
DISCONNECTED,
Ordering::SeqCst,
- );
- cnt != DISCONNECTED && cnt != steals
+ Ordering::SeqCst,
+ ) {
+ Ok(_) => false,
+ Err(old) => old != DISCONNECTED,
+ }
} {
while self.queue.pop().is_some() {
steals += 1;
// must do so with Release ordering to make the result available.
// - `wait` inserts `Waiter` nodes as a pointer in `state_and_queue`, and
// needs to make the nodes available with Release ordering. The load in
-// its `compare_and_swap` can be Relaxed because it only has to compare
+// its `compare_exchange` can be Relaxed because it only has to compare
// the atomic, not to read other data.
// - `WaiterQueue::Drop` must see the `Waiter` nodes, so it must load
// `state_and_queue` with Acquire ordering.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Once {
- // `state_and_queue` is actually an a pointer to a `Waiter` with extra state
+ // `state_and_queue` is actually a pointer to a `Waiter` with extra state
// bits, so we add the `PhantomData` appropriately.
state_and_queue: AtomicUsize,
_marker: marker::PhantomData<*const Waiter>,
}
POISONED | INCOMPLETE => {
// Try to register this thread as the one RUNNING.
- let old = self.state_and_queue.compare_and_swap(
+ let exchange_result = self.state_and_queue.compare_exchange(
state_and_queue,
RUNNING,
Ordering::Acquire,
+ Ordering::Acquire,
);
- if old != state_and_queue {
+ if let Err(old) = exchange_result {
state_and_queue = old;
continue;
}
// Try to slide in the node at the head of the linked list, making sure
// that another thread didn't just replace the head of the linked list.
- let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release);
- if old != current_state {
+ let exchange_result = state_and_queue.compare_exchange(
+ current_state,
+ me | RUNNING,
+ Ordering::Release,
+ Ordering::Relaxed,
+ );
+ if let Err(old) = exchange_result {
current_state = old;
continue;
}
}
// Try to atomically swap UNINIT with BUSY. The returned state can be:
- match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
+ match RELOC_STATE.compare_exchange(UNINIT, BUSY, Ordering::Acquire, Ordering::Acquire) {
// This thread just obtained the lock and other threads will observe BUSY
- UNINIT => {
+ Ok(_) => {
reloc::relocate_elf_rela();
RELOC_STATE.store(DONE, Ordering::Release);
}
// We need to wait until the initialization is done.
- BUSY => {
+ Err(BUSY) => {
while RELOC_STATE.load(Ordering::Acquire) == BUSY {
core::hint::spin_loop();
}
}
// Initialization is done.
- DONE => {}
+ Err(DONE) => {}
_ => unreachable!(),
}
}
#[inline(always)]
pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
- if !self.lock.compare_and_swap(false, true, Ordering::Acquire) {
+ if self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_ok() {
Some(SpinMutexGuard { mutex: self })
} else {
None
// `denom` field.
//
// Encoding this as a single `AtomicU64` allows us to use `Relaxed`
- // operations, as we are only interested in in the effects on a single
+ // operations, as we are only interested in the effects on a single
// memory location.
static INFO_BITS: AtomicU64 = AtomicU64::new(0);
let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) };
inner.remutex.init();
let inner = Box::into_raw(inner);
- match self.lock.compare_and_swap(0, inner as usize, Ordering::SeqCst) {
- 0 => inner,
- n => {
+ match self.lock.compare_exchange(0, inner as usize, Ordering::SeqCst, Ordering::SeqCst) {
+ Ok(_) => inner,
+ Err(n) => {
Box::from_raw(inner).remutex.destroy();
n as *const _
}
// Wait for something to happen, assuming it's still set to PARKED.
c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
// Change NOTIFIED=>EMPTY but leave PARKED alone.
- if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
+ if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
// Actually woken up by unpark().
return;
} else {
}
pub fn verify(&self, mutex: &MovableMutex) {
let addr = mutex.raw() as *const mutex_imp::Mutex as usize;
- match self.addr.compare_and_swap(0, addr, Ordering::SeqCst) {
- 0 => {} // Stored the address
- n if n == addr => {} // Lost a race to store the same address
+ match self.addr.compare_exchange(0, addr, Ordering::SeqCst, Ordering::SeqCst) {
+ Ok(_) => {} // Stored the address
+ Err(n) if n == addr => {} // Lost a race to store the same address
_ => panic!("attempted to use a condition variable with two mutexes"),
}
}
return key;
}
- // POSIX allows the key created here to be 0, but the compare_and_swap
+ // POSIX allows the key created here to be 0, but the compare_exchange
// below relies on using 0 as a sentinel value to check who won the
// race to set the shared TLS key. As far as I know, there is no
// guaranteed value that cannot be returned as a posix_key_create key,
key2
};
rtassert!(key != 0);
- match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
+ match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) {
// The CAS succeeded, so we've created the actual key
- 0 => key as usize,
+ Ok(_) => key as usize,
// If someone beat us to the punch, use their key instead
- n => {
+ Err(n) => {
imp::destroy(key);
n
}
// Wait for something to happen, assuming it's still set to PARKED.
futex_wait(&self.state, PARKED, None);
// Change NOTIFIED=>EMPTY and return in that case.
- if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
+ if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
return;
} else {
// Spurious wake up. We loop to try again.
-Subproject commit f1ed22803f09e3b2c2b86d773db07ce70804987a
+Subproject commit 9c732a56f67f54d12a0b4fd99993154906c95ea6
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
-## [Non-breaking changes since the last major version]
+
+## [Changes since the last major version]
+
+- `llvm-libunwind` now accepts `in-tree` (formerly true), `system` or `no` (formerly false) [#77703](https://github.com/rust-lang/rust/pull/77703)
+
+### Non-breaking changes
- `x.py check` needs opt-in to check tests (--all-targets) [#77473](https://github.com/rust-lang/rust/pull/77473)
- The default bootstrap profiles are now located at `bootstrap/defaults/config.$PROFILE.toml` (previously they were located at `bootstrap/defaults/config.toml.$PROFILE`) [#77558](https://github.com/rust-lang/rust/pull/77558)
# Output for all compiletest-based test suites
test/
ui/
- compile-fail/
debuginfo/
...
with open(tmp, 'w') as f:
yield f
try:
- os.remove(filepath) # PermissionError/OSError on Win32 if in use
- os.rename(tmp, filepath)
+ if os.path.exists(filepath):
+ os.remove(filepath) # PermissionError/OSError on Win32 if in use
except OSError:
shutil.copy2(tmp, filepath)
os.remove(tmp)
+ return
+ os.rename(tmp, filepath)
class RustBuild(object):
test::ExpandYamlAnchors,
test::Tidy,
test::Ui,
- test::CompileFail,
test::RunPassValgrind,
test::MirOpt,
test::Codegen,
dist::RustDev,
dist::Extended,
dist::BuildManifest,
+ dist::ReproducibleArtifacts,
),
Kind::Install => describe!(
install::Docs,
if self.config.deny_warnings {
cmd.arg("-Dwarnings");
}
- // cfg(not(bootstrap)), can be removed on the next beta bump
- if compiler.stage != 0 {
- cmd.arg("-Znormalize-docs");
- }
+ cmd.arg("-Znormalize-docs");
// Remove make-related flags that can cause jobserver problems.
cmd.env_remove("MAKEFLAGS");
//! goes along from the output of the previous stage.
use std::borrow::Cow;
+use std::collections::HashSet;
use std::env;
use std::fs;
use std::io::prelude::*;
let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
rustc_cargo(builder, &mut cargo, target);
+ if builder.config.rust_profile_use.is_some()
+ && builder.config.rust_profile_generate.is_some()
+ {
+ panic!("Cannot use and generate PGO profiles at the same time");
+ }
+
+ let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
+ if compiler.stage == 1 {
+ cargo.rustflag(&format!("-Cprofile-generate={}", path));
+ // Apparently necessary to avoid overflowing the counters during
+ // a Cargo build profile
+ cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4");
+ true
+ } else {
+ false
+ }
+ } else if let Some(path) = &builder.config.rust_profile_use {
+ if compiler.stage == 1 {
+ cargo.rustflag(&format!("-Cprofile-use={}", path));
+ cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ };
+ if is_collecting {
+ // Ensure paths to Rust sources are relative, not absolute.
+ cargo.rustflag(&format!(
+ "-Cllvm-args=-static-func-strip-dirname-prefix={}",
+ builder.config.src.components().count()
+ ));
+ }
+
builder.info(&format!(
"Building stage{} compiler artifacts ({} -> {})",
compiler.stage, &compiler.host, target
// Here we're looking for the output dylib of the `CodegenBackend` step and
// we're copying that into the `codegen-backends` folder.
let dst = builder.sysroot_codegen_backends(target_compiler);
- t!(fs::create_dir_all(&dst));
+ t!(fs::create_dir_all(&dst), dst);
if builder.config.dry_run {
return;
builder.info(&format!("Assembling stage{} compiler ({})", stage, host));
// Link in all dylibs to the libdir
+ let stamp = librustc_stamp(builder, build_compiler, target_compiler.host);
+ let proc_macros = builder
+ .read_stamp_file(&stamp)
+ .into_iter()
+ .filter_map(|(path, dependency_type)| {
+ if dependency_type == DependencyType::Host {
+ Some(path.file_name().unwrap().to_owned().into_string().unwrap())
+ } else {
+ None
+ }
+ })
+ .collect::<HashSet<_>>();
+
let sysroot = builder.sysroot(target_compiler);
let rustc_libdir = builder.rustc_libdir(target_compiler);
t!(fs::create_dir_all(&rustc_libdir));
let src_libdir = builder.sysroot_libdir(build_compiler, host);
for f in builder.read_dir(&src_libdir) {
let filename = f.file_name().into_string().unwrap();
- if is_dylib(&filename) {
+ if is_dylib(&filename) && !proc_macros.contains(&filename) {
builder.copy(&f.path(), &rustc_libdir.join(&filename));
}
}
pub rust_thin_lto_import_instr_limit: Option<u32>,
pub rust_remap_debuginfo: bool,
pub rust_new_symbol_mangling: bool,
+ pub rust_profile_use: Option<String>,
+ pub rust_profile_generate: Option<String>,
pub build: TargetSelection,
pub hosts: Vec<TargetSelection>,
pub dist_sign_folder: Option<PathBuf>,
pub dist_upload_addr: Option<String>,
pub dist_gpg_password_file: Option<PathBuf>,
+ pub dist_compression_formats: Option<Vec<String>>,
// libstd features
pub backtrace: bool, // support for RUST_BACKTRACE
upload_addr: Option<String>,
src_tarball: Option<bool>,
missing_tools: Option<bool>,
+ compression_formats: Option<Vec<String>>,
}
#[derive(Deserialize)]
llvm_libunwind: Option<String>,
control_flow_guard: Option<bool>,
new_symbol_mangling: Option<bool>,
+ profile_generate: Option<String>,
+ profile_use: Option<String>,
}
/// TOML representation of how each build target is configured.
config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
+ config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
+ config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
+ } else {
+ config.rust_profile_use = flags.rust_profile_use;
+ config.rust_profile_generate = flags.rust_profile_generate;
}
if let Some(t) = toml.target {
config.dist_sign_folder = t.sign_folder.map(PathBuf::from);
config.dist_gpg_password_file = t.gpg_password_file.map(PathBuf::from);
config.dist_upload_addr = t.upload_addr;
+ config.dist_compression_formats = t.compression_formats;
set(&mut config.rust_dist_src, t.src_tarball);
set(&mut config.missing_tools, t.missing_tools);
}
"experimental LLVM targets to build")
v("release-channel", "rust.channel", "the name of the release channel to build")
v("release-description", "rust.description", "optional descriptive string for version output")
+v("dist-compression-formats", None,
+ "comma-separated list of compression formats to use")
# Used on systems where "cc" is unavailable
v("default-linker", "rust.default-linker", "the default linker")
elif option.name == 'option-checking':
# this was handled above
pass
+ elif option.name == 'dist-compression-formats':
+ set('dist.compression-formats', value.split(','))
else:
raise RuntimeError("unhandled option {}".format(option.name))
use crate::cache::{Interned, INTERNER};
use crate::compile;
use crate::config::TargetSelection;
+use crate::tarball::{OverlayKind, Tarball};
use crate::tool::{self, Tool};
use crate::util::{exe, is_dylib, timeit};
use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
builder.out.join("tmp/dist")
}
-fn rust_installer(builder: &Builder<'_>) -> Command {
- builder.tool_cmd(Tool::RustInstaller)
-}
-
fn missing_tool(tool_name: &str, skip: bool) {
if skip {
println!("Unable to build {}, skipping dist", tool_name)
}
impl Step for Docs {
- type Output = PathBuf;
+ type Output = Option<PathBuf>;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
}
/// Builds the `rust-docs` installer component.
- fn run(self, builder: &Builder<'_>) -> PathBuf {
+ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
let host = self.host;
-
- let name = pkgname(builder, "rust-docs");
-
if !builder.config.docs {
- return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
+ return None;
}
-
builder.default_doc(None);
- builder.info(&format!("Dist docs ({})", host));
- let _time = timeit(builder);
+ let dest = "share/doc/rust/html";
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
- let _ = fs::remove_dir_all(&image);
-
- let dst = image.join("share/doc/rust/html");
- t!(fs::create_dir_all(&dst));
- let src = builder.doc_out(host);
- builder.cp_r(&src, &dst);
- builder.install(&builder.src.join("src/doc/robots.txt"), &dst, 0o644);
-
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust-Documentation")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Rust-documentation-is-installed.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, host.triple))
- .arg("--component-name=rust-docs")
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--bulk-dirs=share/doc/rust/html");
- builder.run(&mut cmd);
- builder.remove_dir(&image);
-
- distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
+ let mut tarball = Tarball::new(builder, "rust-docs", &host.triple);
+ tarball.set_product_name("Rust Documentation");
+ tarball.add_dir(&builder.doc_out(host), dest);
+ tarball.add_file(&builder.src.join("src/doc/robots.txt"), dest, 0o644);
+ Some(tarball.generate())
}
}
}
impl Step for RustcDocs {
- type Output = PathBuf;
+ type Output = Option<PathBuf>;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
}
/// Builds the `rustc-docs` installer component.
- fn run(self, builder: &Builder<'_>) -> PathBuf {
+ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
let host = self.host;
-
- let name = pkgname(builder, "rustc-docs");
-
if !builder.config.compiler_docs {
- return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
+ return None;
}
-
builder.default_doc(None);
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
- let _ = fs::remove_dir_all(&image);
-
- let dst = image.join("share/doc/rust/html/rustc");
- t!(fs::create_dir_all(&dst));
- let src = builder.compiler_doc_out(host);
- builder.cp_r(&src, &dst);
-
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rustc-Documentation")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Rustc-documentation-is-installed.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, host.triple))
- .arg("--component-name=rustc-docs")
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--bulk-dirs=share/doc/rust/html/rustc");
-
- builder.info(&format!("Dist compiler docs ({})", host));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- builder.remove_dir(&image);
-
- distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
+ let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple);
+ tarball.set_product_name("Rustc Documentation");
+ tarball.add_dir(&builder.compiler_doc_out(host), "share/doc/rust/html/rustc");
+ Some(tarball.generate())
}
}
/// without any extra installed software (e.g., we bundle gcc, libraries, etc).
fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
let host = self.host;
-
if !host.contains("pc-windows-gnu") {
return None;
}
- builder.info(&format!("Dist mingw ({})", host));
- let _time = timeit(builder);
- let name = pkgname(builder, "rust-mingw");
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
- let _ = fs::remove_dir_all(&image);
- t!(fs::create_dir_all(&image));
+ let mut tarball = Tarball::new(builder, "rust-mingw", &host.triple);
+ tarball.set_product_name("Rust MinGW");
// The first argument is a "temporary directory" which is just
// thrown away (this contains the runtime DLLs included in the rustc package
// above) and the second argument is where to place all the MinGW components
// (which is what we want).
- make_win_dist(&tmpdir(builder), &image, host, &builder);
-
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust-MinGW")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Rust-MinGW-is-installed.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, host.triple))
- .arg("--component-name=rust-mingw")
- .arg("--legacy-manifest-dirs=rustlib,cargo");
- builder.run(&mut cmd);
- t!(fs::remove_dir_all(&image));
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)))
+ make_win_dist(&tmpdir(builder), tarball.image_dir(), host, &builder);
+
+ Some(tarball.generate())
}
}
let compiler = self.compiler;
let host = self.compiler.host;
- let name = pkgname(builder, "rustc");
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
- let _ = fs::remove_dir_all(&image);
- let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host.triple));
- let _ = fs::remove_dir_all(&overlay);
+ let tarball = Tarball::new(builder, "rustc", &host.triple);
// Prepare the rustc "image", what will actually end up getting installed
- prepare_image(builder, compiler, &image);
-
- // Prepare the overlay which is part of the tarball but won't actually be
- // installed
- let cp = |file: &str| {
- builder.install(&builder.src.join(file), &overlay, 0o644);
- };
- cp("COPYRIGHT");
- cp("LICENSE-APACHE");
- cp("LICENSE-MIT");
- cp("README.md");
- // tiny morsel of metadata is used by rust-packaging
- let version = builder.rust_version();
- builder.create(&overlay.join("version"), &version);
- if let Some(sha) = builder.rust_sha() {
- builder.create(&overlay.join("git-commit-hash"), &sha);
- }
+ prepare_image(builder, compiler, tarball.image_dir());
// On MinGW we've got a few runtime DLL dependencies that we need to
// include. The first argument to this script is where to put these DLLs
// install will *also* include the rust-mingw package, which also needs
// licenses, so to be safe we just include it here in all MinGW packages.
if host.contains("pc-windows-gnu") {
- make_win_dist(&image, &tmpdir(builder), host, builder);
-
- let dst = image.join("share/doc");
- t!(fs::create_dir_all(&dst));
- builder.cp_r(&builder.src.join("src/etc/third-party"), &dst);
+ make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder);
+ tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
}
- // Finally, wrap everything up in a nice tarball!
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Rust-is-ready-to-roll.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, host.triple))
- .arg("--component-name=rustc")
- .arg("--legacy-manifest-dirs=rustlib,cargo");
-
- builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host.triple));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- builder.remove_dir(&image);
- builder.remove_dir(&overlay);
-
- return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
+ return tarball.generate();
fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
let host = compiler.host;
}
impl Step for Std {
- type Output = PathBuf;
+ type Output = Option<PathBuf>;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
});
}
- fn run(self, builder: &Builder<'_>) -> PathBuf {
+ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
let compiler = self.compiler;
let target = self.target;
- let name = pkgname(builder, "rust-std");
- let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
if skip_host_target_lib(builder, compiler) {
- return archive;
+ return None;
}
builder.ensure(compile::Std { compiler, target });
- let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
- let _ = fs::remove_dir_all(&image);
+ let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
+ tarball.include_target_in_component_name(true);
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
let stamp = compile::libstd_stamp(builder, compiler_to_use, target);
- copy_target_libs(builder, target, &image, &stamp);
-
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=std-is-standing-at-the-ready.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg(format!("--component-name=rust-std-{}", target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo");
-
- builder
- .info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- builder.remove_dir(&image);
- archive
+ copy_target_libs(builder, target, &tarball.image_dir(), &stamp);
+
+ Some(tarball.generate())
}
}
}
impl Step for RustcDev {
- type Output = PathBuf;
+ type Output = Option<PathBuf>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
});
}
- fn run(self, builder: &Builder<'_>) -> PathBuf {
+ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
let compiler = self.compiler;
let target = self.target;
-
- let name = pkgname(builder, "rustc-dev");
- let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
if skip_host_target_lib(builder, compiler) {
- return archive;
+ return None;
}
builder.ensure(compile::Rustc { compiler, target });
- let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
- let _ = fs::remove_dir_all(&image);
+ let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
let stamp = compile::librustc_stamp(builder, compiler_to_use, target);
- copy_target_libs(builder, target, &image, &stamp);
-
- // Copy compiler sources.
- let dst_src = image.join("lib/rustlib/rustc-src/rust");
- t!(fs::create_dir_all(&dst_src));
+ copy_target_libs(builder, target, tarball.image_dir(), &stamp);
- let src_files = ["Cargo.lock"];
+ let src_files = &["Cargo.lock"];
// This is the reduced set of paths which will become the rustc-dev component
// (essentially the compiler crates and all of their path dependencies).
- copy_src_dirs(builder, &builder.src, &["compiler"], &[], &dst_src);
- for file in src_files.iter() {
- builder.copy(&builder.src.join(file), &dst_src.join(file));
+ copy_src_dirs(
+ builder,
+ &builder.src,
+ &["compiler"],
+ &[],
+ &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
+ );
+ for file in src_files {
+ tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644);
}
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Rust-is-ready-to-develop.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg(format!("--component-name=rustc-dev-{}", target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo");
-
- builder.info(&format!(
- "Dist rustc-dev stage{} ({} -> {})",
- compiler.stage, &compiler.host, target
- ));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- builder.remove_dir(&image);
- archive
+ Some(tarball.generate())
}
}
}
impl Step for Analysis {
- type Output = PathBuf;
+ type Output = Option<PathBuf>;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
}
/// Creates a tarball of save-analysis metadata, if available.
- fn run(self, builder: &Builder<'_>) -> PathBuf {
+ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
let compiler = self.compiler;
let target = self.target;
assert!(builder.config.extended);
- let name = pkgname(builder, "rust-analysis");
-
if compiler.host != builder.config.build {
- return distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
+ return None;
}
builder.ensure(compile::Std { compiler, target });
-
- let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
-
let src = builder
.stage_out(compiler, Mode::Std)
.join(target.triple)
.join(builder.cargo_dir())
- .join("deps");
+ .join("deps")
+ .join("save-analysis");
- let image_src = src.join("save-analysis");
- let dst = image.join("lib/rustlib").join(target.triple).join("analysis");
- t!(fs::create_dir_all(&dst));
- builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
- builder.cp_r(&image_src, &dst);
-
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=save-analysis-saved.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg(format!("--component-name=rust-analysis-{}", target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo");
-
- builder.info("Dist analysis");
- let _time = timeit(builder);
- builder.run(&mut cmd);
- builder.remove_dir(&image);
- distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
+ let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple);
+ tarball.include_target_in_component_name(true);
+ tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple));
+ Some(tarball.generate())
}
}
/// Creates the `rust-src` installer component
fn run(self, builder: &Builder<'_>) -> PathBuf {
- let name = pkgname(builder, "rust-src");
- let image = tmpdir(builder).join(format!("{}-image", name));
- let _ = fs::remove_dir_all(&image);
+ let tarball = Tarball::new_targetless(builder, "rust-src");
// A lot of tools expect the rust-src component to be entirely in this directory, so if you
// change that (e.g. by adding another directory `lib/rustlib/src/foo` or
//
// NOTE: if you update the paths here, you also should update the "virtual" path
// translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
- let dst_src = image.join("lib/rustlib/src/rust");
- t!(fs::create_dir_all(&dst_src));
+ let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
let src_files = ["Cargo.lock"];
// This is the reduced set of paths which will become the rust-src component
builder.copy(&builder.src.join(file), &dst_src.join(file));
}
- // Create source tarball in rust-installer format
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Awesome-Source.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}", name))
- .arg("--component-name=rust-src")
- .arg("--legacy-manifest-dirs=rustlib,cargo");
-
- builder.info("Dist src");
- let _time = timeit(builder);
- builder.run(&mut cmd);
-
- builder.remove_dir(&image);
- distdir(builder).join(&format!("{}.tar.gz", name))
+ tarball.generate()
}
}
/// Creates the plain source tarball
fn run(self, builder: &Builder<'_>) -> PathBuf {
- // Make sure that the root folder of tarball has the correct name
- let plain_name = format!("{}-src", pkgname(builder, "rustc"));
- let plain_dst_src = tmpdir(builder).join(&plain_name);
- let _ = fs::remove_dir_all(&plain_dst_src);
- t!(fs::create_dir_all(&plain_dst_src));
+ let tarball = Tarball::new(builder, "rustc", "src");
+ let plain_dst_src = tarball.image_dir();
// This is the set of root paths which will become part of the source package
let src_files = [
builder.run(&mut cmd);
}
- // Create plain source tarball
- let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
- let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
- tarball.set_extension(""); // strip .gz
- tarball.set_extension(""); // strip .tar
- if let Some(dir) = tarball.parent() {
- builder.create_dir(&dir);
- }
- builder.info("running installer");
- let mut cmd = rust_installer(builder);
- cmd.arg("tarball")
- .arg("--input")
- .arg(&plain_name)
- .arg("--output")
- .arg(&tarball)
- .arg("--work-dir=.")
- .current_dir(tmpdir(builder));
-
- builder.info("Create plain source tarball");
- let _time = timeit(builder);
- builder.run(&mut cmd);
- distdir(builder).join(&format!("{}.tar.gz", plain_name))
+ tarball.bare()
}
}
let compiler = self.compiler;
let target = self.target;
+ let cargo = builder.ensure(tool::Cargo { compiler, target });
let src = builder.src.join("src/tools/cargo");
let etc = src.join("src/etc");
- let release_num = builder.release_num("cargo");
- let name = pkgname(builder, "cargo");
- let version = builder.cargo_info.version(builder, &release_num);
-
- let tmp = tmpdir(builder);
- let image = tmp.join("cargo-image");
- drop(fs::remove_dir_all(&image));
- builder.create_dir(&image);
// Prepare the image directory
- builder.create_dir(&image.join("share/zsh/site-functions"));
- builder.create_dir(&image.join("etc/bash_completion.d"));
- let cargo = builder.ensure(tool::Cargo { compiler, target });
- builder.install(&cargo, &image.join("bin"), 0o755);
+ let mut tarball = Tarball::new(builder, "cargo", &target.triple);
+ tarball.set_overlay(OverlayKind::Cargo);
+
+ tarball.add_file(&cargo, "bin", 0o755);
+ tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
+ tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo");
+ tarball.add_dir(etc.join("man"), "share/man/man1");
+ tarball.add_legal_and_readme_to("share/doc/cargo");
+
for dirent in fs::read_dir(cargo.parent().unwrap()).expect("read_dir") {
let dirent = dirent.expect("read dir entry");
if dirent.file_name().to_str().expect("utf8").starts_with("cargo-credential-") {
- builder.install(&dirent.path(), &image.join("libexec"), 0o755);
+ tarball.add_file(&dirent.path(), "libexec", 0o755);
}
}
- for man in t!(etc.join("man").read_dir()) {
- let man = t!(man);
- builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
- }
- builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
- builder.copy(&etc.join("cargo.bashcomp.sh"), &image.join("etc/bash_completion.d/cargo"));
- let doc = image.join("share/doc/cargo");
- builder.install(&src.join("README.md"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
-
- // Prepare the overlay
- let overlay = tmp.join("cargo-overlay");
- drop(fs::remove_dir_all(&overlay));
- builder.create_dir(&overlay);
- builder.install(&src.join("README.md"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
- builder.create(&overlay.join("version"), &version);
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Rust-is-ready-to-roll.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--component-name=cargo")
- .arg("--legacy-manifest-dirs=rustlib,cargo");
-
- builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
+
+ tarball.generate()
}
}
let target = self.target;
assert!(builder.config.extended);
- let src = builder.src.join("src/tools/rls");
- let release_num = builder.release_num("rls");
- let name = pkgname(builder, "rls");
- let version = builder.rls_info.version(builder, &release_num);
-
- let tmp = tmpdir(builder);
- let image = tmp.join("rls-image");
- drop(fs::remove_dir_all(&image));
- t!(fs::create_dir_all(&image));
-
- // Prepare the image directory
- // We expect RLS to build, because we've exited this step above if tool
- // state for RLS isn't testing.
let rls = builder
.ensure(tool::Rls { compiler, target, extra_features: Vec::new() })
.or_else(|| {
None
})?;
- builder.install(&rls, &image.join("bin"), 0o755);
- let doc = image.join("share/doc/rls");
- builder.install(&src.join("README.md"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-
- // Prepare the overlay
- let overlay = tmp.join("rls-overlay");
- drop(fs::remove_dir_all(&overlay));
- t!(fs::create_dir_all(&overlay));
- builder.install(&src.join("README.md"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
- builder.create(&overlay.join("version"), &version);
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=RLS-ready-to-serve.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=rls-preview");
-
- builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target.triple));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+ let mut tarball = Tarball::new(builder, "rls", &target.triple);
+ tarball.set_overlay(OverlayKind::RLS);
+ tarball.is_preview(true);
+ tarball.add_file(rls, "bin", 0o755);
+ tarball.add_legal_and_readme_to("share/doc/rls");
+ Some(tarball.generate())
}
}
return None;
}
- let src = builder.src.join("src/tools/rust-analyzer");
- let release_num = builder.release_num("rust-analyzer/crates/rust-analyzer");
- let name = pkgname(builder, "rust-analyzer");
- let version = builder.rust_analyzer_info.version(builder, &release_num);
-
- let tmp = tmpdir(builder);
- let image = tmp.join("rust-analyzer-image");
- drop(fs::remove_dir_all(&image));
- builder.create_dir(&image);
-
- // Prepare the image directory
- // We expect rust-analyer to always build, as it doesn't depend on rustc internals
- // and doesn't have associated toolstate.
let rust_analyzer = builder
.ensure(tool::RustAnalyzer { compiler, target, extra_features: Vec::new() })
.expect("rust-analyzer always builds");
- builder.install(&rust_analyzer, &image.join("bin"), 0o755);
- let doc = image.join("share/doc/rust-analyzer");
- builder.install(&src.join("README.md"), &doc, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-
- // Prepare the overlay
- let overlay = tmp.join("rust-analyzer-overlay");
- drop(fs::remove_dir_all(&overlay));
- t!(fs::create_dir_all(&overlay));
- builder.install(&src.join("README.md"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- builder.create(&overlay.join("version"), &version);
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=rust-analyzer-ready-to-serve.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=rust-analyzer-preview");
-
- builder.info(&format!("Dist rust-analyzer stage{} ({})", compiler.stage, target));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+ let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
+ tarball.set_overlay(OverlayKind::RustAnalyzer);
+ tarball.is_preview(true);
+ tarball.add_file(rust_analyzer, "bin", 0o755);
+ tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
+ Some(tarball.generate())
}
}
let target = self.target;
assert!(builder.config.extended);
- let src = builder.src.join("src/tools/clippy");
- let release_num = builder.release_num("clippy");
- let name = pkgname(builder, "clippy");
- let version = builder.clippy_info.version(builder, &release_num);
-
- let tmp = tmpdir(builder);
- let image = tmp.join("clippy-image");
- drop(fs::remove_dir_all(&image));
- builder.create_dir(&image);
-
// Prepare the image directory
// We expect clippy to build, because we've exited this step above if tool
// state for clippy isn't testing.
.ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() })
.expect("clippy expected to build - essential tool");
- builder.install(&clippy, &image.join("bin"), 0o755);
- builder.install(&cargoclippy, &image.join("bin"), 0o755);
- let doc = image.join("share/doc/clippy");
- builder.install(&src.join("README.md"), &doc, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-
- // Prepare the overlay
- let overlay = tmp.join("clippy-overlay");
- drop(fs::remove_dir_all(&overlay));
- t!(fs::create_dir_all(&overlay));
- builder.install(&src.join("README.md"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- builder.create(&overlay.join("version"), &version);
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=clippy-ready-to-serve.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=clippy-preview");
-
- builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
+ let mut tarball = Tarball::new(builder, "clippy", &target.triple);
+ tarball.set_overlay(OverlayKind::Clippy);
+ tarball.is_preview(true);
+ tarball.add_file(clippy, "bin", 0o755);
+ tarball.add_file(cargoclippy, "bin", 0o755);
+ tarball.add_legal_and_readme_to("share/doc/clippy");
+ tarball.generate()
}
}
let target = self.target;
assert!(builder.config.extended);
- let src = builder.src.join("src/tools/miri");
- let release_num = builder.release_num("miri");
- let name = pkgname(builder, "miri");
- let version = builder.miri_info.version(builder, &release_num);
-
- let tmp = tmpdir(builder);
- let image = tmp.join("miri-image");
- drop(fs::remove_dir_all(&image));
- builder.create_dir(&image);
-
- // Prepare the image directory
- // We expect miri to build, because we've exited this step above if tool
- // state for miri isn't testing.
let miri = builder
.ensure(tool::Miri { compiler, target, extra_features: Vec::new() })
.or_else(|| {
None
})?;
- builder.install(&miri, &image.join("bin"), 0o755);
- builder.install(&cargomiri, &image.join("bin"), 0o755);
- let doc = image.join("share/doc/miri");
- builder.install(&src.join("README.md"), &doc, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
-
- // Prepare the overlay
- let overlay = tmp.join("miri-overlay");
- drop(fs::remove_dir_all(&overlay));
- t!(fs::create_dir_all(&overlay));
- builder.install(&src.join("README.md"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- builder.create(&overlay.join("version"), &version);
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=miri-ready-to-serve.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=miri-preview");
-
- builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+ let mut tarball = Tarball::new(builder, "miri", &target.triple);
+ tarball.set_overlay(OverlayKind::Miri);
+ tarball.is_preview(true);
+ tarball.add_file(miri, "bin", 0o755);
+ tarball.add_file(cargomiri, "bin", 0o755);
+ tarball.add_legal_and_readme_to("share/doc/miri");
+ Some(tarball.generate())
}
}
let compiler = self.compiler;
let target = self.target;
- let src = builder.src.join("src/tools/rustfmt");
- let release_num = builder.release_num("rustfmt");
- let name = pkgname(builder, "rustfmt");
- let version = builder.rustfmt_info.version(builder, &release_num);
-
- let tmp = tmpdir(builder);
- let image = tmp.join("rustfmt-image");
- drop(fs::remove_dir_all(&image));
- builder.create_dir(&image);
-
- // Prepare the image directory
let rustfmt = builder
.ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() })
.or_else(|| {
None
})?;
- builder.install(&rustfmt, &image.join("bin"), 0o755);
- builder.install(&cargofmt, &image.join("bin"), 0o755);
- let doc = image.join("share/doc/rustfmt");
- builder.install(&src.join("README.md"), &doc, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
-
- // Prepare the overlay
- let overlay = tmp.join("rustfmt-overlay");
- drop(fs::remove_dir_all(&overlay));
- builder.create_dir(&overlay);
- builder.install(&src.join("README.md"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
- builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
- builder.create(&overlay.join("version"), &version);
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=rustfmt-ready-to-fmt.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=rustfmt-preview");
-
- builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target));
- let _time = timeit(builder);
- builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+ let mut tarball = Tarball::new(builder, "rustfmt", &target.triple);
+ tarball.set_overlay(OverlayKind::Rustfmt);
+ tarball.is_preview(true);
+ tarball.add_file(rustfmt, "bin", 0o755);
+ tarball.add_file(cargofmt, "bin", 0o755);
+ tarball.add_legal_and_readme_to("share/doc/rustfmt");
+ Some(tarball.generate())
}
}
let analysis_installer = builder.ensure(Analysis { compiler, target });
let docs_installer = builder.ensure(Docs { host: target });
- let std_installer =
- builder.ensure(Std { compiler: builder.compiler(stage, target), target });
+ let std_installer = builder.ensure(Std { compiler, target });
- let tmp = tmpdir(builder);
- let overlay = tmp.join("extended-overlay");
let etc = builder.src.join("src/etc/installer");
- let work = tmp.join("work");
-
- let _ = fs::remove_dir_all(&overlay);
- builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
- builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
- builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
- let version = builder.rust_version();
- builder.create(&overlay.join("version"), &version);
- if let Some(sha) = builder.rust_sha() {
- builder.create(&overlay.join("git-commit-hash"), &sha);
+
+ // Avoid producing tarballs during a dry run.
+ if builder.config.dry_run {
+ return;
}
- builder.install(&etc.join("README.md"), &overlay, 0o644);
// When rust-std package split from rustc, we needed to ensure that during
// upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
tarballs.extend(miri_installer.clone());
tarballs.extend(rustfmt_installer.clone());
tarballs.extend(llvm_tools_installer);
- tarballs.push(analysis_installer);
- tarballs.push(std_installer);
- if builder.config.docs {
+ if let Some(analysis_installer) = analysis_installer {
+ tarballs.push(analysis_installer);
+ }
+ tarballs.push(std_installer.expect("missing std"));
+ if let Some(docs_installer) = docs_installer {
tarballs.push(docs_installer);
}
if target.contains("pc-windows-gnu") {
tarballs.push(mingw_installer.unwrap());
}
- let mut input_tarballs = tarballs[0].as_os_str().to_owned();
- for tarball in &tarballs[1..] {
- input_tarballs.push(",");
- input_tarballs.push(tarball);
- }
- builder.info("building combined installer");
- let mut cmd = rust_installer(builder);
- cmd.arg("combine")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=Rust-is-ready-to-roll.")
- .arg("--work-dir")
- .arg(&work)
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--input-tarballs")
- .arg(input_tarballs)
- .arg("--non-installed-overlay")
- .arg(&overlay);
- let time = timeit(&builder);
- builder.run(&mut cmd);
- drop(time);
+ let mut tarball = Tarball::new(builder, "rust", &target.triple);
+ let work = tarball.persist_work_dir();
+ tarball.combine(&tarballs);
+
+ let tmp = tmpdir(builder).join("combined-tarball");
let mut license = String::new();
license += &builder.read(&builder.src.join("COPYRIGHT"));
}
}
- builder.info(&format!("Dist LlvmTools ({})", target));
- let _time = timeit(builder);
- let src = builder.src.join("src/llvm-project/llvm");
- let name = pkgname(builder, "llvm-tools");
-
- let tmp = tmpdir(builder);
- let image = tmp.join("llvm-tools-image");
- drop(fs::remove_dir_all(&image));
+ let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
+ tarball.set_overlay(OverlayKind::LLVM);
+ tarball.is_preview(true);
// Prepare the image directory
let src_bindir = builder.llvm_out(target).join("bin");
- let dst_bindir = image.join("lib/rustlib").join(&*target.triple).join("bin");
- t!(fs::create_dir_all(&dst_bindir));
+ let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
for tool in LLVM_TOOLS {
let exe = src_bindir.join(exe(tool, target));
- builder.install(&exe, &dst_bindir, 0o755);
+ tarball.add_file(&exe, &dst_bindir, 0o755);
}
// Copy libLLVM.so to the target lib dir as well, so the RPATH like
// `$ORIGIN/../lib` can find it. It may also be used as a dependency
// of `rustc-dev` to support the inherited `-lLLVM` when using the
// compiler libraries.
- maybe_install_llvm_target(builder, target, &image);
-
- // Prepare the overlay
- let overlay = tmp.join("llvm-tools-overlay");
- drop(fs::remove_dir_all(&overlay));
- builder.create_dir(&overlay);
- builder.install(&src.join("README.txt"), &overlay, 0o644);
- builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
- builder.create(&overlay.join("version"), &builder.llvm_tools_vers());
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=llvm-tools-installed.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=llvm-tools-preview");
-
- builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+ maybe_install_llvm_target(builder, target, tarball.image_dir());
+
+ Some(tarball.generate())
}
}
}
}
- builder.info(&format!("Dist RustDev ({})", target));
- let _time = timeit(builder);
- let src = builder.src.join("src/llvm-project/llvm");
- let name = pkgname(builder, "rust-dev");
-
- let tmp = tmpdir(builder);
- let image = tmp.join("rust-dev-image");
- drop(fs::remove_dir_all(&image));
-
- // Prepare the image directory
- let dst_bindir = image.join("bin");
- t!(fs::create_dir_all(&dst_bindir));
+ let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
+ tarball.set_overlay(OverlayKind::LLVM);
let src_bindir = builder.llvm_out(target).join("bin");
- let install_bin =
- |name| builder.install(&src_bindir.join(exe(name, target)), &dst_bindir, 0o755);
- install_bin("llvm-config");
- install_bin("llvm-ar");
- install_bin("llvm-objdump");
- install_bin("llvm-profdata");
- install_bin("llvm-bcanalyzer");
- install_bin("llvm-cov");
- install_bin("llvm-dwp");
- builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755);
+ for bin in &[
+ "llvm-config",
+ "llvm-ar",
+ "llvm-objdump",
+ "llvm-profdata",
+ "llvm-bcanalyzer",
+ "llvm-cov",
+ "llvm-dwp",
+ ] {
+ tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
+ }
+ tarball.add_file(&builder.llvm_filecheck(target), "bin", 0o755);
// Copy the include directory as well; needed mostly to build
// librustc_llvm properly (e.g., llvm-config.h is in here). But also
// just broadly useful to be able to link against the bundled LLVM.
- builder.cp_r(&builder.llvm_out(target).join("include"), &image.join("include"));
+ tarball.add_dir(&builder.llvm_out(target).join("include"), "include");
// Copy libLLVM.so to the target lib dir as well, so the RPATH like
// `$ORIGIN/../lib` can find it. It may also be used as a dependency
// of `rustc-dev` to support the inherited `-lLLVM` when using the
// compiler libraries.
- maybe_install_llvm(builder, target, &image.join("lib"));
-
- // Prepare the overlay
- let overlay = tmp.join("rust-dev-overlay");
- drop(fs::remove_dir_all(&overlay));
- builder.create_dir(&overlay);
- builder.install(&src.join("README.txt"), &overlay, 0o644);
- builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
- builder.create(&overlay.join("version"), &builder.rust_version());
-
- // Generate the installer tarball
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=rust-dev-installed.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=rust-dev");
-
- builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
+ maybe_install_llvm(builder, target, &tarball.image_dir().join("lib"));
+
+ Some(tarball.generate())
}
}
fn run(self, builder: &Builder<'_>) -> PathBuf {
let build_manifest = builder.tool_exe(Tool::BuildManifest);
- let name = pkgname(builder, "build-manifest");
- let tmp = tmpdir(builder);
-
- // Prepare the image.
- let image = tmp.join("build-manifest-image");
- let image_bin = image.join("bin");
- let _ = fs::remove_dir_all(&image);
- t!(fs::create_dir_all(&image_bin));
- builder.install(&build_manifest, &image_bin, 0o755);
-
- // Prepare the overlay.
- let overlay = tmp.join("build-manifest-overlay");
- let _ = fs::remove_dir_all(&overlay);
- builder.create_dir(&overlay);
- builder.create(&overlay.join("version"), &builder.rust_version());
- for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] {
- builder.install(&builder.src.join(file), &overlay, 0o644);
- }
+ let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
+ tarball.add_file(&build_manifest, "bin", 0o755);
+ tarball.generate()
+ }
+}
+
+/// Tarball containing artifacts necessary to reproduce the build of rustc.
+///
+/// Currently this is the PGO profile data.
+///
+/// Should not be considered stable by end users.
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct ReproducibleArtifacts {
+ pub target: TargetSelection,
+}
+
+impl Step for ReproducibleArtifacts {
+ type Output = Option<PathBuf>;
+ const DEFAULT: bool = true;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.path("reproducible")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(ReproducibleArtifacts { target: run.target });
+ }
+
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ let path = builder.config.rust_profile_use.as_ref()?;
- // Create the final tarball.
- let mut cmd = rust_installer(builder);
- cmd.arg("generate")
- .arg("--product-name=Rust")
- .arg("--rel-manifest-dir=rustlib")
- .arg("--success-message=build-manifest installed.")
- .arg("--image-dir")
- .arg(&image)
- .arg("--work-dir")
- .arg(&tmpdir(builder))
- .arg("--output-dir")
- .arg(&distdir(builder))
- .arg("--non-installed-overlay")
- .arg(&overlay)
- .arg(format!("--package-name={}-{}", name, self.target.triple))
- .arg("--legacy-manifest-dirs=rustlib,cargo")
- .arg("--component-name=build-manifest");
-
- builder.run(&mut cmd);
- distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple))
+ let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
+ tarball.add_file(path, ".", 0o644);
+ Some(tarball.generate())
}
}
let target = self.target;
builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
- // This is the intended out directory for compiler documentation.
- let out = builder.compiler_doc_out(target);
- t!(fs::create_dir_all(&out));
-
- let compiler = builder.compiler(stage, builder.config.build);
-
if !builder.config.compiler_docs {
builder.info("\tskipping - compiler/librustdoc docs disabled");
return;
}
+ // This is the intended out directory for compiler documentation.
+ let out = builder.compiler_doc_out(target);
+ t!(fs::create_dir_all(&out));
+
// Build rustc.
+ let compiler = builder.compiler(stage, builder.config.build);
builder.ensure(compile::Rustc { compiler, target });
// This uses a shared directory so that librustdoc documentation gets
// merging the search index, or generating local (relative) links.
let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
t!(symlink_dir_force(&builder.config, &out, &out_dir));
+ // Cargo puts proc macros in `target/doc` even if you pass `--target`
+ // explicitly (https://github.com/rust-lang/cargo/issues/7677).
+ let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc");
+ t!(symlink_dir_force(&builder.config, &out, &proc_macro_out_dir));
// Build cargo command.
let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
cargo.rustdocflag("--document-private-items");
cargo.rustdocflag("--enable-index-page");
cargo.rustdocflag("-Zunstable-options");
- // cfg(not(bootstrap)), can be removed on the next beta bump
- if stage != 0 {
- cargo.rustdocflag("-Znormalize-docs");
- }
+ cargo.rustdocflag("-Znormalize-docs");
compile::rustc_cargo(builder, &mut cargo, target);
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("-p").arg("rustdoc");
cargo.rustdocflag("--document-private-items");
+ cargo.rustdocflag("--enable-index-page");
+ cargo.rustdocflag("-Zunstable-options");
builder.run(&mut cargo.into());
}
}
pub deny_warnings: Option<bool>,
pub llvm_skip_rebuild: Option<bool>,
+
+ pub rust_profile_use: Option<String>,
+ pub rust_profile_generate: Option<String>,
}
pub enum Subcommand {
VALUE overrides the skip-rebuild option in config.toml.",
"VALUE",
);
+ opts.optopt("", "rust-profile-generate", "rustc error format", "FORMAT");
+ opts.optopt("", "rust-profile-use", "rustc error format", "FORMAT");
// We can't use getopt to parse the options until we have completed specifying which
// options are valid, but under the current implementation, some options are conditional on
color: matches
.opt_get_default("color", Color::Auto)
.expect("`color` should be `always`, `never`, or `auto`"),
+ rust_profile_use: matches.opt_str("rust-profile-use"),
+ rust_profile_generate: matches.opt_str("rust-profile-generate"),
}
}
}
mod run;
mod sanity;
mod setup;
+mod tarball;
mod test;
mod tool;
mod toolstate;
self.package_vers(&self.version)
}
- fn llvm_tools_vers(&self) -> String {
- self.rust_version()
- }
-
fn llvm_link_tools_dynamically(&self, target: TargetSelection) -> bool {
target.contains("linux-gnu") || target.contains("apple-darwin")
}
TESTS_IN_2 := \
src/test/ui \
- src/test/compile-fail \
src/tools/linkchecker
ci-subset-1:
$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2)
TESTS_IN_MINGW_2 := \
- src/test/ui \
- src/test/compile-fail
+ src/test/ui
ci-mingw-subset-1:
$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
--- /dev/null
+use std::{
+ path::{Path, PathBuf},
+ process::Command,
+};
+
+use build_helper::t;
+
+use crate::builder::Builder;
+
+#[derive(Copy, Clone)]
+pub(crate) enum OverlayKind {
+ Rust,
+ LLVM,
+ Cargo,
+ Clippy,
+ Miri,
+ Rustfmt,
+ RLS,
+ RustAnalyzer,
+}
+
+impl OverlayKind {
+ fn legal_and_readme(&self) -> &[&str] {
+ match self {
+ OverlayKind::Rust => &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"],
+ OverlayKind::LLVM => {
+ &["src/llvm-project/llvm/LICENSE.TXT", "src/llvm-project/llvm/README.txt"]
+ }
+ OverlayKind::Cargo => &[
+ "src/tools/cargo/README.md",
+ "src/tools/cargo/LICENSE-MIT",
+ "src/tools/cargo/LICENSE-APACHE",
+ "src/tools/cargo/LICENSE-THIRD-PARTY",
+ ],
+ OverlayKind::Clippy => &[
+ "src/tools/clippy/README.md",
+ "src/tools/clippy/LICENSE-APACHE",
+ "src/tools/clippy/LICENSE-MIT",
+ ],
+ OverlayKind::Miri => &[
+ "src/tools/miri/README.md",
+ "src/tools/miri/LICENSE-APACHE",
+ "src/tools/miri/LICENSE-MIT",
+ ],
+ OverlayKind::Rustfmt => &[
+ "src/tools/rustfmt/README.md",
+ "src/tools/rustfmt/LICENSE-APACHE",
+ "src/tools/rustfmt/LICENSE-MIT",
+ ],
+ OverlayKind::RLS => &[
+ "src/tools/rls/README.md",
+ "src/tools/rls/LICENSE-APACHE",
+ "src/tools/rls/LICENSE-MIT",
+ ],
+ OverlayKind::RustAnalyzer => &[
+ "src/tools/rust-analyzer/README.md",
+ "src/tools/rust-analyzer/LICENSE-APACHE",
+ "src/tools/rust-analyzer/LICENSE-MIT",
+ ],
+ }
+ }
+
+ fn version(&self, builder: &Builder<'_>) -> String {
+ match self {
+ OverlayKind::Rust => builder.rust_version(),
+ OverlayKind::LLVM => builder.rust_version(),
+ OverlayKind::Cargo => {
+ builder.cargo_info.version(builder, &builder.release_num("cargo"))
+ }
+ OverlayKind::Clippy => {
+ builder.clippy_info.version(builder, &builder.release_num("clippy"))
+ }
+ OverlayKind::Miri => builder.miri_info.version(builder, &builder.release_num("miri")),
+ OverlayKind::Rustfmt => {
+ builder.rustfmt_info.version(builder, &builder.release_num("rustfmt"))
+ }
+ OverlayKind::RLS => builder.rls_info.version(builder, &builder.release_num("rls")),
+ OverlayKind::RustAnalyzer => builder
+ .rust_analyzer_info
+ .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")),
+ }
+ }
+}
+
+pub(crate) struct Tarball<'a> {
+ builder: &'a Builder<'a>,
+
+ pkgname: String,
+ component: String,
+ target: Option<String>,
+ product_name: String,
+ overlay: OverlayKind,
+
+ temp_dir: PathBuf,
+ image_dir: PathBuf,
+ overlay_dir: PathBuf,
+
+ include_target_in_component_name: bool,
+ is_preview: bool,
+ delete_temp_dir: bool,
+}
+
+impl<'a> Tarball<'a> {
+ pub(crate) fn new(builder: &'a Builder<'a>, component: &str, target: &str) -> Self {
+ Self::new_inner(builder, component, Some(target.into()))
+ }
+
+ pub(crate) fn new_targetless(builder: &'a Builder<'a>, component: &str) -> Self {
+ Self::new_inner(builder, component, None)
+ }
+
+ fn new_inner(builder: &'a Builder<'a>, component: &str, target: Option<String>) -> Self {
+ let pkgname = crate::dist::pkgname(builder, component);
+
+ let mut temp_dir = builder.out.join("tmp").join("tarball").join(component);
+ if let Some(target) = &target {
+ temp_dir = temp_dir.join(target);
+ }
+ let _ = std::fs::remove_dir_all(&temp_dir);
+
+ let image_dir = temp_dir.join("image");
+ let overlay_dir = temp_dir.join("overlay");
+
+ Self {
+ builder,
+
+ pkgname,
+ component: component.into(),
+ target,
+ product_name: "Rust".into(),
+ overlay: OverlayKind::Rust,
+
+ temp_dir,
+ image_dir,
+ overlay_dir,
+
+ include_target_in_component_name: false,
+ is_preview: false,
+ delete_temp_dir: true,
+ }
+ }
+
+ pub(crate) fn set_overlay(&mut self, overlay: OverlayKind) {
+ self.overlay = overlay;
+ }
+
+ pub(crate) fn set_product_name(&mut self, name: &str) {
+ self.product_name = name.into();
+ }
+
+ pub(crate) fn include_target_in_component_name(&mut self, include: bool) {
+ self.include_target_in_component_name = include;
+ }
+
+ pub(crate) fn is_preview(&mut self, is: bool) {
+ self.is_preview = is;
+ }
+
+ pub(crate) fn image_dir(&self) -> &Path {
+ t!(std::fs::create_dir_all(&self.image_dir));
+ &self.image_dir
+ }
+
+ pub(crate) fn add_file(&self, src: impl AsRef<Path>, destdir: impl AsRef<Path>, perms: u32) {
+ // create_dir_all fails to create `foo/bar/.`, so when the destination is "." this simply
+ // uses the base directory as the destination directory.
+ let destdir = if destdir.as_ref() == Path::new(".") {
+ self.image_dir.clone()
+ } else {
+ self.image_dir.join(destdir.as_ref())
+ };
+
+ t!(std::fs::create_dir_all(&destdir));
+ self.builder.install(src.as_ref(), &destdir, perms);
+ }
+
+ pub(crate) fn add_renamed_file(
+ &self,
+ src: impl AsRef<Path>,
+ destdir: impl AsRef<Path>,
+ new_name: &str,
+ ) {
+ let destdir = self.image_dir.join(destdir.as_ref());
+ t!(std::fs::create_dir_all(&destdir));
+ self.builder.copy(src.as_ref(), &destdir.join(new_name));
+ }
+
+ pub(crate) fn add_legal_and_readme_to(&self, destdir: impl AsRef<Path>) {
+ for file in self.overlay.legal_and_readme() {
+ self.add_file(self.builder.src.join(file), destdir.as_ref(), 0o644);
+ }
+ }
+
+ pub(crate) fn add_dir(&self, src: impl AsRef<Path>, dest: impl AsRef<Path>) {
+ let dest = self.image_dir.join(dest.as_ref());
+
+ t!(std::fs::create_dir_all(&dest));
+ self.builder.cp_r(src.as_ref(), &dest);
+ }
+
+ pub(crate) fn persist_work_dir(&mut self) -> PathBuf {
+ self.delete_temp_dir = false;
+ self.temp_dir.clone()
+ }
+
+ pub(crate) fn generate(self) -> PathBuf {
+ let mut component_name = self.component.clone();
+ if self.is_preview {
+ component_name.push_str("-preview");
+ }
+ if self.include_target_in_component_name {
+ component_name.push('-');
+ component_name.push_str(
+ &self
+ .target
+ .as_ref()
+ .expect("include_target_in_component_name used in a targetless tarball"),
+ );
+ }
+
+ self.run(|this, cmd| {
+ cmd.arg("generate")
+ .arg("--image-dir")
+ .arg(&this.image_dir)
+ .arg(format!("--component-name={}", &component_name));
+ this.non_bare_args(cmd);
+ })
+ }
+
+ pub(crate) fn combine(self, tarballs: &[PathBuf]) {
+ let mut input_tarballs = tarballs[0].as_os_str().to_os_string();
+ for tarball in &tarballs[1..] {
+ input_tarballs.push(",");
+ input_tarballs.push(tarball);
+ }
+
+ self.run(|this, cmd| {
+ cmd.arg("combine").arg("--input-tarballs").arg(input_tarballs);
+ this.non_bare_args(cmd);
+ });
+ }
+
+ pub(crate) fn bare(self) -> PathBuf {
+ // Bare tarballs should have the top level directory match the package
+ // name, not "image". We rename the image directory just before passing
+ // into rust-installer.
+ let dest = self.temp_dir.join(self.package_name());
+ t!(std::fs::rename(&self.image_dir, &dest));
+
+ self.run(|this, cmd| {
+ cmd.arg("tarball")
+ .arg("--input")
+ .arg(&dest)
+ .arg("--output")
+ .arg(crate::dist::distdir(this.builder).join(this.package_name()));
+ })
+ }
+
+ fn package_name(&self) -> String {
+ if let Some(target) = &self.target {
+ format!("{}-{}", self.pkgname, target)
+ } else {
+ self.pkgname.clone()
+ }
+ }
+
+ fn non_bare_args(&self, cmd: &mut Command) {
+ cmd.arg("--rel-manifest-dir=rustlib")
+ .arg("--legacy-manifest-dirs=rustlib,cargo")
+ .arg(format!("--product-name={}", self.product_name))
+ .arg(format!("--success-message={} installed.", self.component))
+ .arg(format!("--package-name={}", self.package_name()))
+ .arg("--non-installed-overlay")
+ .arg(&self.overlay_dir)
+ .arg("--output-dir")
+ .arg(crate::dist::distdir(self.builder));
+ }
+
+ fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> PathBuf {
+ t!(std::fs::create_dir_all(&self.overlay_dir));
+ self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder));
+ if let Some(sha) = self.builder.rust_sha() {
+ self.builder.create(&self.overlay_dir.join("git-commit-hash"), &sha);
+ }
+ for file in self.overlay.legal_and_readme() {
+ self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);
+ }
+
+ let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller);
+
+ let package_name = self.package_name();
+ self.builder.info(&format!("Dist {}", package_name));
+ let _time = crate::util::timeit(self.builder);
+
+ build_cli(&self, &mut cmd);
+ cmd.arg("--work-dir").arg(&self.temp_dir);
+ if let Some(formats) = &self.builder.config.dist_compression_formats {
+ assert!(!formats.is_empty(), "dist.compression-formats can't be empty");
+ cmd.arg("--compression-formats").arg(formats.join(","));
+ }
+ self.builder.run(&mut cmd);
+ if self.delete_temp_dir {
+ t!(std::fs::remove_dir_all(&self.temp_dir));
+ }
+
+ // Use either the first compression format defined, or "gz" as the default.
+ let ext = self
+ .builder
+ .config
+ .dist_compression_formats
+ .as_ref()
+ .and_then(|formats| formats.get(0))
+ .map(|s| s.as_str())
+ .unwrap_or("gz");
+
+ crate::dist::distdir(self.builder).join(format!("{}.tar.{}", package_name, ext))
+ }
+}
compare_mode: "nll"
});
-default_test!(CompileFail {
- path: "src/test/compile-fail",
- mode: "compile-fail",
- suite: "compile-fail"
-});
-
default_test!(RunPassValgrind {
path: "src/test/run-pass-valgrind",
mode: "run-pass-valgrind",
builder.ensure(dist::Src);
let mut cmd = Command::new("tar");
- cmd.arg("-xzf")
+ cmd.arg("-xf")
.arg(builder.ensure(dist::PlainSourceTarball))
.arg("--strip-components=1")
.current_dir(&dir);
t!(fs::create_dir_all(&dir));
let mut cmd = Command::new("tar");
- cmd.arg("-xzf")
- .arg(builder.ensure(dist::Src))
- .arg("--strip-components=1")
- .current_dir(&dir);
+ cmd.arg("-xf").arg(builder.ensure(dist::Src)).arg("--strip-components=1").current_dir(&dir);
builder.run(&mut cmd);
let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
+ENV PGO_HOST=x86_64-unknown-linux-gnu
+
ENV HOSTS=x86_64-unknown-linux-gnu
ENV RUST_CONFIGURE_ARGS \
--set llvm.thin-lto=true \
--set llvm.ninja=false \
--set rust.jemalloc
-ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \
- --include-default-paths \
- src/tools/build-manifest
+ENV SCRIPT ../src/ci/pgo.sh python2.7 ../x.py dist \
+ --host $HOSTS --target $HOSTS \
+ --include-default-paths \
+ src/tools/build-manifest
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
# This is the only builder which will create source tarballs
ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
src/test/run-make \
src/test/ui \
- src/test/compile-fail \
src/test/mir-opt \
src/test/codegen-units \
library/core
--- /dev/null
+#!/bin/bash
+
+set -euxo pipefail
+
+rm -rf /tmp/rustc-pgo
+
+python2.7 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
+ --stage 2 library/std --rust-profile-generate=/tmp/rustc-pgo
+
+./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
+ --crate-type=lib ../library/core/src/lib.rs
+
+# Download and build a single-file stress test benchmark on perf.rust-lang.org.
+function pgo_perf_benchmark {
+ local PERF=e095f5021bf01cf3800f50b3a9f14a9683eb3e4e
+ local github_prefix=https://raw.githubusercontent.com/rust-lang/rustc-perf/$PERF
+ local name=$1
+ curl -o /tmp/$name.rs $github_prefix/collector/benchmarks/$name/src/lib.rs
+ ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 --crate-type=lib /tmp/$name.rs
+}
+
+pgo_perf_benchmark externs
+pgo_perf_benchmark ctfe-stress-4
+
+cp -pri ../src/tools/cargo /tmp/cargo
+
+# Build cargo (with some flags)
+function pgo_cargo {
+ RUSTC=./build/$PGO_HOST/stage2/bin/rustc \
+ ./build/$PGO_HOST/stage0/bin/cargo $@ \
+ --manifest-path /tmp/cargo/Cargo.toml
+}
+
+# Build a couple different variants of Cargo
+CARGO_INCREMENTAL=1 pgo_cargo check
+echo 'pub fn barbarbar() {}' >> /tmp/cargo/src/cargo/lib.rs
+CARGO_INCREMENTAL=1 pgo_cargo check
+touch /tmp/cargo/src/cargo/lib.rs
+CARGO_INCREMENTAL=1 pgo_cargo check
+pgo_cargo build --release
+
+# Merge the profile data we gathered
+./build/$PGO_HOST/llvm/bin/llvm-profdata \
+ merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo
+
+# This produces the actual final set of artifacts.
+$@ --rust-profile-use=/tmp/rustc-pgo.profdata
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1"
+# Only produce xz tarballs on CI. gz tarballs will be generated by the release
+# process by recompressing the existing xz ones. This decreases the storage
+# space required for CI artifacts.
+RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz"
+
if [ "$DIST_SRC" = "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src"
fi
-Subproject commit a190438d77d28041f24da4f6592e287fab073a61
+Subproject commit 5bb44f8b5b0aa105c8b22602e9b18800484afa21
-Subproject commit d8383b65f7948c2ca19191b3b4bd709b403aaf45
+Subproject commit a5a48441d411f61556b57d762b03d6874afe575d
-Subproject commit a8afdca5d0715b2257b6f8b9a032fd4dd7dae855
+Subproject commit b278478b766178491a8b6f67afa4bcd6b64d977a
-Subproject commit 236c734a2cb323541b3394f98682cb981b9ec086
+Subproject commit 1cce0737d6a7d3ceafb139b4a206861fb1dcb2ab
multilingual = false
src = "src"
title = "The rustc book"
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
authors = ["The Rust Project Developers"]
src = "src"
title = "The rustdoc book"
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc"
All of the usual caveats of cross-compiling code apply.
+## `--default-theme`: set the default theme
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc src/lib.rs --default-theme=ayu
+```
+
+Sets the default theme (for users whose browser has not remembered a
+previous theme selection from the on-page theme picker).
+
+The supplied value should be the lowercase version of the theme name.
+The set of available themes can be seen in the theme picker in the
+generated output.
+
+Note that the set of available themes - and their appearance - is not
+necessarily stable from one rustdoc version to the next. If the
+requested theme does not exist, the builtin default (currently
+`light`) is used instead.
+
## `--markdown-css`: include more CSS files when rendering markdown
Using this flag looks like this:
Let's give it a try! Create a new project with Cargo:
```bash
-$ cargo new docs
+$ cargo new docs --lib
$ cd docs
```
referentially-transparent, and are therefore more relaxed than `#[ffi_const]`
functions.
-However, accesing global memory through volatile or atomic reads can violate the
+However, accessing global memory through volatile or atomic reads can violate the
requirement that two consecutive function calls shall return the same value.
A `pure` function that returns unit has no effect on the abstract machine's
#!/usr/bin/env python
"""
-This script creates a pile of compile-fail tests check that all the
+This script creates a pile of UI tests check that all the
derives have spans that point to the fields, rather than the
#[derive(...)] line.
<DisplayString>{data_ptr,[length]s8}</DisplayString>
<StringView>data_ptr,[length]s8</StringView>
<Expand>
- <Item Name="[size]" ExcludeView="simple">length</Item>
- <ArrayItems>
- <Size>length</Size>
- <ValuePointer>data_ptr</ValuePointer>
- </ArrayItems>
+ <Item Name="[len]" ExcludeView="simple">length</Item>
+ <Synthetic Name="[chars]">
+ <Expand>
+ <ArrayItems>
+ <Size>length</Size>
+ <ValuePointer>data_ptr</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Synthetic>
</Expand>
</Type>
<Type Name="slice<*>">
- <DisplayString>{{ length={length} }}</DisplayString>
+ <DisplayString>{{ len={length} }}</DisplayString>
<Expand>
- <Item Name="[size]" ExcludeView="simple">length</Item>
+ <Item Name="[len]" ExcludeView="simple">length</Item>
<ArrayItems>
<Size>length</Size>
<ValuePointer>data_ptr</ValuePointer>
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="alloc::vec::Vec<*>">
- <DisplayString>{{ size={len} }}</DisplayString>
+ <DisplayString>{{ len={len} }}</DisplayString>
<Expand>
- <Item Name="[size]" ExcludeView="simple">len</Item>
+ <Item Name="[len]" ExcludeView="simple">len</Item>
<Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
<ArrayItems>
<Size>len</Size>
</Expand>
</Type>
<Type Name="alloc::collections::vec_deque::VecDeque<*>">
- <DisplayString>{{ size={tail <= head ? head - tail : buf.cap - tail + head} }}</DisplayString>
+ <DisplayString>{{ len={tail <= head ? head - tail : buf.cap - tail + head} }}</DisplayString>
<Expand>
- <Item Name="[size]" ExcludeView="simple">tail <= head ? head - tail : buf.cap - tail + head</Item>
+ <Item Name="[len]" ExcludeView="simple">tail <= head ? head - tail : buf.cap - tail + head</Item>
<Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
<CustomListItems>
<Variable Name="i" InitialValue="tail" />
</Expand>
</Type>
<Type Name="alloc::collections::linked_list::LinkedList<*>">
- <DisplayString>{{ size={len} }}</DisplayString>
+ <DisplayString>{{ len={len} }}</DisplayString>
<Expand>
<LinkedListItems>
<Size>len</Size>
</Expand>
</Type>
<Type Name="alloc::string::String">
- <DisplayString>{*(char**)this,[vec.len]s8}</DisplayString>
- <StringView>*(char**)this,[vec.len]s8</StringView>
+ <DisplayString>{(char*)vec.buf.ptr.pointer,[vec.len]s8}</DisplayString>
+ <StringView>(char*)vec.buf.ptr.pointer,[vec.len]s8</StringView>
<Expand>
- <Item Name="[size]" ExcludeView="simple">vec.len</Item>
+ <Item Name="[len]" ExcludeView="simple">vec.len</Item>
<Item Name="[capacity]" ExcludeView="simple">vec.buf.cap</Item>
- <ArrayItems>
- <Size>vec.len</Size>
- <ValuePointer>*(char**)this</ValuePointer>
- </ArrayItems>
+ <Synthetic Name="[chars]">
+ <Expand>
+ <ArrayItems>
+ <Size>vec.len</Size>
+ <ValuePointer>(char*)vec.buf.ptr.pointer</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Synthetic>
+ </Expand>
+ </Type>
+ <Type Name="alloc::rc::Rc<*>">
+ <DisplayString>{ptr.pointer->value}</DisplayString>
+ <Expand>
+ <ExpandedItem>ptr.pointer->value</ExpandedItem>
+ </Expand>
+ </Type>
+ <Type Name="alloc::sync::Arc<*>">
+ <DisplayString>{ptr.pointer->data}</DisplayString>
+ <Expand>
+ <ExpandedItem>ptr.pointer->data</ExpandedItem>
+ </Expand>
+ </Type>
+ <Type Name="alloc::sync::Weak<*>">
+ <DisplayString>{ptr.pointer->data}</DisplayString>
+ <Expand>
+ <ExpandedItem>ptr.pointer->data</ExpandedItem>
</Expand>
</Type>
</AutoVisualizer>
<Item Name="[ptr]">pointer</Item>
</Expand>
</Type>
+
<Type Name="core::ptr::Shared<*>">
<DisplayString>{{ Shared {pointer} }}</DisplayString>
<Expand>
<Item Name="[ptr]">pointer</Item>
</Expand>
</Type>
+
<Type Name="core::option::Option<*>">
- <DisplayString Condition="RUST$ENUM$DISR == 0x0">{{ None }}</DisplayString>
- <DisplayString Condition="RUST$ENUM$DISR == 0x1">{{ Some {__0} }}</DisplayString>
+ <DisplayString Condition="RUST$ENUM$DISR == 0x0">None</DisplayString>
+ <DisplayString Condition="RUST$ENUM$DISR == 0x1">Some({__0})</DisplayString>
<Expand>
- <Item Name="[size]" ExcludeView="simple">(ULONG)(RUST$ENUM$DISR != 0)</Item>
- <Item Name="[value]" ExcludeView="simple">__0</Item>
- <ArrayItems>
- <Size>(ULONG)(RUST$ENUM$DISR != 0)</Size>
- <ValuePointer>&__0</ValuePointer>
- </ArrayItems>
+ <Item Name="[value]" ExcludeView="simple" Condition="RUST$ENUM$DISR == 1">__0</Item>
</Expand>
</Type>
+
<Type Name="core::option::Option<*>" Priority="MediumLow">
- <DisplayString Condition="*(PVOID *)this == nullptr">{{ None }}</DisplayString>
- <DisplayString>{{ Some {($T1 *)this} }}</DisplayString>
+ <DisplayString Condition="*(void**)this == nullptr">None</DisplayString>
+ <DisplayString>Some({($T1 *)this})</DisplayString>
<Expand>
- <Item Name="[size]" ExcludeView="simple">(ULONG)(*(PVOID *)this != nullptr)</Item>
- <Item Name="[value]" ExcludeView="simple" Condition="*(PVOID *)this != nullptr">($T1 *)this</Item>
- <ArrayItems>
- <Size>(ULONG)(*(PVOID *)this != nullptr)</Size>
- <ValuePointer>($T1 *)this</ValuePointer>
- </ArrayItems>
+ <Item Name="Some" ExcludeView="simple" Condition="*(void**)this != nullptr">($T1 *)this</Item>
</Expand>
</Type>
+
</AutoVisualizer>
\ No newline at end of file
-->
<Type Name="std::collections::hash::map::HashMap<*,*,*>">
- <DisplayString>{{ size={base.table.items} }}</DisplayString>
+ <DisplayString>{{ len={base.table.items} }}</DisplayString>
<Expand>
- <Item Name="[size]">base.table.items</Item>
+ <Item Name="[len]">base.table.items</Item>
<Item Name="[capacity]">base.table.items + base.table.growth_left</Item>
<Item Name="[state]">base.hash_builder</Item>
</Type>
<Type Name="std::collections::hash::set::HashSet<*,*>">
- <DisplayString>{{ size={base.map.table.items} }}</DisplayString>
+ <DisplayString>{{ len={base.map.table.items} }}</DisplayString>
<Expand>
- <Item Name="[size]">base.map.table.items</Item>
+ <Item Name="[len]">base.map.table.items</Item>
<Item Name="[capacity]">base.map.table.items + base.map.table.growth_left</Item>
<Item Name="[state]">base.map.hash_builder</Item>
attrs: Default::default(),
visibility: Inherited,
def_id: self.cx.next_def_id(param_env_def_id.krate),
- stability: None,
- const_stability: None,
- deprecation: None,
- kind: ImplItem(Impl {
+ kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: new_generics,
provided_trait_methods: Default::default(),
ref mut bindings, ..
} => {
bindings.push(TypeBinding {
- name: left_name.clone(),
+ name: left_name,
kind: TypeBindingKind::Equality { ty: rhs },
});
}
GenericParamDefKind::Type { ref mut default, ref mut bounds, .. } => {
// We never want something like `impl<T=Foo>`.
default.take();
- let generic_ty = Type::Generic(param.name.clone());
+ let generic_ty = Type::Generic(param.name);
if !has_sized.contains(&generic_ty) {
bounds.insert(0, GenericBound::maybe_sized(self.cx));
}
attrs: Default::default(),
visibility: Inherited,
def_id: self.cx.next_def_id(impl_def_id.krate),
- stability: None,
- const_stability: None,
- deprecation: None,
- kind: ImplItem(Impl {
+ kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: (
self.cx.tcx.generics_of(impl_def_id),
source: clean::Span::dummy(),
def_id: DefId::local(CRATE_DEF_INDEX),
visibility: clean::Public,
- stability: None,
- const_stability: None,
- deprecation: None,
- kind: clean::ImportItem(clean::Import::new_simple(
+ kind: box clean::ImportItem(clean::Import::new_simple(
item.ident.name,
clean::ImportSource {
path: clean::Path {
impl Clean<Item> for doctree::Module<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
- // maintain a stack of mod ids, for doc comment path resolution
- // but we also need to resolve the module's own docs based on whether its docs were written
- // inside or outside the module, so check for that
- let attrs = self.attrs.clean(cx);
-
let mut items: Vec<Item> = vec![];
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
ModuleItem(Module { is_crate: self.is_crate, items }),
cx,
);
- Item { attrs, source: span.clean(cx), ..what_rustc_thinks }
+ Item { source: span.clean(cx), ..what_rustc_thinks }
}
}
_ => false,
}
}
+ /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
+ ///
+ /// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
+ ///
+ /// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
+ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
+ match param.kind {
+ hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided } => true,
+ _ => false,
+ }
+ }
+
let impl_trait_params = self
.params
.iter()
.collect::<Vec<_>>();
let mut params = Vec::with_capacity(self.params.len());
- for p in self.params.iter().filter(|p| !is_impl_trait(p)) {
+ for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
let p = p.clean(cx);
params.push(p);
}
where_predicates.retain(|pred| match *pred {
WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
if bounds.iter().any(|b| b.is_sized_bound(cx)) {
- sized_params.insert(g.clone());
+ sized_params.insert(*g);
false
} else {
true
&& !sized_params.contains(&tp.name)
{
where_predicates.push(WP::BoundPredicate {
- ty: Type::Generic(tp.name.clone()),
+ ty: Type::Generic(tp.name),
bounds: vec![GenericBound::maybe_sized(cx)],
})
}
.iter()
.enumerate()
.map(|(i, ty)| {
- let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Invalid);
+ let mut name = self.1.get(i).map(|ident| ident.name).unwrap_or(kw::Empty);
if name.is_empty() {
name = kw::Underscore;
}
.iter()
.map(|t| Argument {
type_: t.clean(cx),
- name: names.next().map(|i| i.name).unwrap_or(kw::Invalid),
+ name: names.next().map(|i| i.name).unwrap_or(kw::Empty),
})
.collect(),
},
TyKind::Never => Never,
TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)),
TyKind::Rptr(ref l, ref m) => {
- let lifetime = if l.is_elided() { None } else { Some(l.clean(cx)) };
+ // There are two times a `Fresh` lifetime can be created:
+ // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
+ // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
+ // See #59286 for more information.
+ // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
+ // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
+ // there's no case where it could cause the function to fail to compile.
+ let elided =
+ l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
+ let lifetime = if elided { None } else { Some(l.clean(cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
}
TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
hir::VisibilityKind::Inherited => Visibility::Inherited,
hir::VisibilityKind::Crate(_) => {
let krate = DefId::local(CRATE_DEF_INDEX);
- Visibility::Restricted(krate, cx.tcx.def_path(krate))
+ Visibility::Restricted(krate)
}
hir::VisibilityKind::Restricted { ref path, .. } => {
let path = path.clean(cx);
let did = register_res(cx, path.res);
- Visibility::Restricted(did, cx.tcx.def_path(did))
+ Visibility::Restricted(did)
}
}
}
}
impl Clean<Visibility> for ty::Visibility {
- fn clean(&self, cx: &DocContext<'_>) -> Visibility {
+ fn clean(&self, _cx: &DocContext<'_>) -> Visibility {
match *self {
ty::Visibility::Public => Visibility::Public,
+ // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
+ // while rustdoc really does mean inherited. That means that for enum variants, such as
+ // `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc.
+ // This is the main reason `impl Clean for hir::Visibility` still exists; various parts of clean
+ // override `tcx.visibility` explicitly to make sure this distinction is captured.
ty::Visibility::Invisible => Visibility::Inherited,
- ty::Visibility::Restricted(module) => {
- Visibility::Restricted(module, cx.tcx.def_path(module))
- }
+ ty::Visibility::Restricted(module) => Visibility::Restricted(module),
}
}
}
source: krate.span.clean(cx),
def_id: crate_def_id,
visibility: krate.vis.clean(cx),
- stability: None,
- const_stability: None,
- deprecation: None,
- kind: ExternCrateItem(name, orig_name),
+ kind: box ExternCrateItem(name, orig_name),
}]
}
source: self.span.clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
visibility: self.vis.clean(cx),
- stability: None,
- const_stability: None,
- deprecation: None,
- kind: ImportItem(Import::new_simple(
+ kind: box ImportItem(Import::new_simple(
self.name,
resolve_use_source(cx, path),
false,
source: self.span.clean(cx),
def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
visibility: self.vis.clean(cx),
- stability: None,
- const_stability: None,
- deprecation: None,
- kind: ImportItem(inner),
+ kind: box ImportItem(inner),
}]
}
}
if matchers.len() <= 1 {
format!(
"{}macro {}{} {{\n ...\n}}",
- vis.print_with_space(),
+ vis.print_with_space(cx.tcx),
name,
matchers.iter().map(|span| span.to_src(cx)).collect::<String>(),
)
} else {
format!(
"{}macro {} {{\n{}}}",
- vis.print_with_space(),
+ vis.print_with_space(cx.tcx),
name,
matchers
.iter()
crate name: Option<Symbol>,
crate attrs: Attributes,
crate visibility: Visibility,
- crate kind: ItemKind,
+ crate kind: Box<ItemKind>,
crate def_id: DefId,
- crate stability: Option<Stability>,
- crate deprecation: Option<Deprecation>,
- crate const_stability: Option<ConstStability>,
}
+// `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Item, 136);
+
impl fmt::Debug for Item {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
.field("kind", &self.kind)
.field("visibility", &self.visibility)
.field("def_id", def_id)
- .field("stability", &self.stability)
- .field("deprecation", &self.deprecation)
.finish()
}
}
impl Item {
+ crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
+ if self.is_fake() { None } else { tcx.lookup_stability(self.def_id) }
+ }
+
+ crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
+ if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id) }
+ }
+
+ crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
+ if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) }
+ }
+
/// Finds the `doc` attribute as a NameValue and returns the corresponding
/// value found.
crate fn doc_value(&self) -> Option<&str> {
Item {
def_id,
- kind,
+ kind: box kind,
name,
source: source.clean(cx),
attrs: cx.tcx.get_attrs(def_id).clean(cx),
visibility: cx.tcx.visibility(def_id).clean(cx),
- stability: cx.tcx.lookup_stability(def_id).cloned(),
- deprecation: cx.tcx.lookup_deprecation(def_id),
- const_stability: cx.tcx.lookup_const_stability(def_id).cloned(),
}
}
}
crate fn is_crate(&self) -> bool {
- match self.kind {
+ match *self.kind {
StrippedItem(box ModuleItem(Module { is_crate: true, .. }))
| ModuleItem(Module { is_crate: true, .. }) => true,
_ => false,
self.type_() == ItemType::Keyword
}
crate fn is_stripped(&self) -> bool {
- match self.kind {
+ match *self.kind {
StrippedItem(..) => true,
ImportItem(ref i) => !i.should_be_displayed,
_ => false,
}
}
crate fn has_stripped_fields(&self) -> Option<bool> {
- match self.kind {
+ match *self.kind {
StructItem(ref _struct) => Some(_struct.fields_stripped),
UnionItem(ref union) => Some(union.fields_stripped),
VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => {
}
}
- crate fn stability_class(&self) -> Option<String> {
- self.stability.as_ref().and_then(|ref s| {
+ crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
+ self.stability(tcx).as_ref().and_then(|ref s| {
let mut classes = Vec::with_capacity(2);
if s.level.is_unstable() {
}
// FIXME: what about non-staged API items that are deprecated?
- if self.deprecation.is_some() {
+ if self.deprecation(tcx).is_some() {
classes.push("deprecated");
}
})
}
- crate fn stable_since(&self) -> Option<SymbolStr> {
- match self.stability?.level {
+ crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+ match self.stability(tcx)?.level {
StabilityLevel::Stable { since, .. } => Some(since.as_str()),
StabilityLevel::Unstable { .. } => None,
}
}
- crate fn const_stable_since(&self) -> Option<SymbolStr> {
- match self.const_stability?.level {
+ crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+ match self.const_stability(tcx)?.level {
StabilityLevel::Stable { since, .. } => Some(since.as_str()),
StabilityLevel::Unstable { .. } => None,
}
}
crate fn is_default(&self) -> bool {
- match self.kind {
+ match *self.kind {
ItemKind::MethodItem(_, Some(defaultness)) => {
defaultness.has_value() && !defaultness.is_final()
}
let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
if let Some(value) = attr.doc_str() {
trace!("got doc_str={:?}", value);
- let value = beautify_doc_string(value);
+ let value = beautify_doc_string(value).to_string();
let kind = if attr.is_doc_comment() {
DocFragmentKind::SugaredDoc
} else {
}
}
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
crate enum Visibility {
Public,
Inherited,
- Restricted(DefId, rustc_hir::definitions::DefPath),
+ Restricted(DefId),
}
impl Visibility {
};
use crate::core::DocContext;
-use itertools::Itertools;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
let mut module = module.clean(cx);
let mut masked_crates = FxHashSet::default();
- match module.kind {
+ match *module.kind {
ItemKind::ModuleItem(ref module) => {
for it in &module.items {
// `compiler_builtins` should be masked too, but we can't apply
let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
{
- let m = match module.kind {
+ let m = match *module.kind {
ItemKind::ModuleItem(ref mut m) => m,
_ => unreachable!(),
};
)
}));
m.items.extend(keywords.into_iter().map(|(def_id, kw)| {
- Item::from_def_id_and_parts(def_id, Some(kw.clone()), ItemKind::KeywordItem(kw), cx)
+ Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem(kw), cx)
}));
}
.segments
.iter()
.map(|s| PathSegment {
- name: s.name.clone(),
+ name: s.name,
args: GenericArgs::AngleBracketed { args: vec![], bindings: vec![] },
})
.collect();
let tcx = cx.tcx;
for item in items {
- let target = match item.kind {
+ let target = match *item.kind {
ItemKind::TypedefItem(ref t, true) => &t.type_,
_ => continue,
};
ty: Ty<'tcx>,
param_env_def_id: DefId,
) -> impl Iterator<Item = Item> {
- AutoTraitFinder::new(cx)
- .get_auto_trait_impls(ty, param_env_def_id)
- .into_iter()
- .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id))
+ let auto_impls = cx.sess().time("get_auto_trait_impls", || {
+ AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id)
+ });
+ let blanket_impls = cx.sess().time("get_blanket_impls", || {
+ BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id)
+ });
+ auto_impls.into_iter().chain(blanket_impls)
}
crate fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
edition: Edition,
outdir: DirState,
path: PathBuf,
+ test_id: &str,
) -> Result<(), TestFailure> {
let (test, line_offset, supports_color) =
- make_test(test, Some(cratename), as_test_harness, opts, edition);
+ make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id));
let output_file = outdir.path().join("rust_out");
dont_insert_main: bool,
opts: &TestOptions,
edition: Edition,
+ test_id: Option<&str>,
) -> (String, usize, bool) {
let (crate_attrs, everything_else, crates) = partition_source(s);
let everything_else = everything_else.trim();
prog.push_str(everything_else);
} else {
let returns_result = everything_else.trim_end().ends_with("(())");
+ // Give each doctest main function a unique name.
+ // This is for example needed for the tooling around `-Z instrument-coverage`.
+ let inner_fn_name = if let Some(test_id) = test_id {
+ format!("_doctest_main_{}", test_id)
+ } else {
+ "_inner".into()
+ };
+ let inner_attr = if test_id.is_some() { "#[allow(non_snake_case)] " } else { "" };
let (main_pre, main_post) = if returns_result {
(
- "fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {",
- "}\n_inner().unwrap() }",
+ format!(
+ "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n",
+ inner_attr, inner_fn_name
+ ),
+ format!("\n}} {}().unwrap() }}", inner_fn_name),
+ )
+ } else if test_id.is_some() {
+ (
+ format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name),
+ format!("\n}} {}() }}", inner_fn_name),
)
} else {
- ("fn main() {\n", "\n}")
+ ("fn main() {\n".into(), "\n}".into())
};
- prog.extend([main_pre, everything_else, main_post].iter().cloned());
+ // Note on newlines: We insert a line/newline *before*, and *after*
+ // the doctest and adjust the `line_offset` accordingly.
+ // In the case of `-Z instrument-coverage`, this means that the generated
+ // inner `main` function spans from the doctest opening codeblock to the
+ // closing one. For example
+ // /// ``` <- start of the inner main
+ // /// <- code under doctest
+ // /// ``` <- end of the inner main
line_offset += 1;
+
+ prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
}
debug!("final doctest:\n{}", prog);
_ => PathBuf::from(r"doctest.rs"),
};
+ // For example `module/file.rs` would become `module_file_rs`
+ let file = filename
+ .to_string()
+ .chars()
+ .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
+ .collect::<String>();
+ let test_id = format!(
+ "{file}_{line}_{number}",
+ file = file,
+ line = line,
+ number = {
+ // Increases the current test number, if this file already
+ // exists or it creates a new entry with a test number of 0.
+ self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0)
+ },
+ );
let outdir = if let Some(mut path) = options.persist_doctests.clone() {
- // For example `module/file.rs` would become `module_file_rs`
- let folder_name = filename
- .to_string()
- .chars()
- .map(|c| if c == '\\' || c == '/' || c == '.' { '_' } else { c })
- .collect::<String>();
-
- path.push(format!(
- "{krate}_{file}_{line}_{number}",
- krate = cratename,
- file = folder_name,
- line = line,
- number = {
- // Increases the current test number, if this file already
- // exists or it creates a new entry with a test number of 0.
- self.visited_tests
- .entry((folder_name.clone(), line))
- .and_modify(|v| *v += 1)
- .or_insert(0)
- },
- ));
+ path.push(&test_id);
std::fs::create_dir_all(&path)
.expect("Couldn't create directory for doctest executables");
edition,
outdir,
path,
+ &test_id,
);
if let Err(err) = res {
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 3));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 3));
// Adding more will also bump the returned line offset.
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 4));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 1));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
//Ceci n'est pas une `fn main`
assert_eq!(2+2, 4);"
.to_string();
- let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 1));
}
assert_eq!(2+2, 4);
}"
.to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 1));
}
}"
.to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
let input = "extern crate hella_qwop;
}"
.to_string();
- let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 3));
}
}"
.to_string();
- let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
+ let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 1));
}
+
+#[test]
+fn make_test_returns_result() {
+ // creates an inner function and unwraps it
+ let opts = TestOptions::default();
+ let input = "use std::io;
+let mut input = String::new();
+io::stdin().read_line(&mut input)?;
+Ok::<(), io:Error>(())";
+ let expected = "#![allow(unused)]
+fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {
+use std::io;
+let mut input = String::new();
+io::stdin().read_line(&mut input)?;
+Ok::<(), io:Error>(())
+} _inner().unwrap() }"
+ .to_string();
+ let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
+ assert_eq!((output, len), (expected, 2));
+}
+
+#[test]
+fn make_test_named_wrapper() {
+ // creates an inner function with a specific name
+ let opts = TestOptions::default();
+ let input = "assert_eq!(2+2, 4);";
+ let expected = "#![allow(unused)]
+fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() {
+assert_eq!(2+2, 4);
+} _doctest_main__some_unique_name() }"
+ .to_string();
+ let (output, len, _) =
+ make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name"));
+ assert_eq!((output, len), (expected, 2));
+}
crate struct Module<'hir> {
crate name: Option<Symbol>,
- crate attrs: &'hir [ast::Attribute],
crate where_outer: Span,
crate where_inner: Span,
crate imports: Vec<Import<'hir>>,
}
impl Module<'hir> {
- crate fn new(name: Option<Symbol>, attrs: &'hir [ast::Attribute]) -> Module<'hir> {
+ crate fn new(name: Option<Symbol>) -> Module<'hir> {
Module {
name,
id: hir::CRATE_HIR_ID,
where_outer: rustc_span::DUMMY_SP,
where_inner: rustc_span::DUMMY_SP,
- attrs,
imports: Vec::new(),
mods: Vec::new(),
items: Vec::new(),
crate struct StripItem(pub Item);
impl StripItem {
- crate fn strip(self) -> Option<Item> {
+ crate fn strip(self) -> Item {
match self.0 {
- Item { kind: StrippedItem(..), .. } => Some(self.0),
+ Item { kind: box StrippedItem(..), .. } => self.0,
mut i => {
- i.kind = StrippedItem(box i.kind);
- Some(i)
+ i.kind = box StrippedItem(i.kind);
+ i
}
}
}
/// don't override!
fn fold_item_recur(&mut self, mut item: Item) -> Item {
- item.kind = match item.kind {
+ item.kind = box match *item.kind {
StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
- _ => self.fold_inner_recur(item.kind),
+ _ => self.fold_inner_recur(*item.kind),
};
item
}
// If this is a stripped module,
// we don't want it or its children in the search index.
- let orig_stripped_mod = match item.kind {
+ let orig_stripped_mod = match *item.kind {
clean::StrippedItem(box clean::ModuleItem(..)) => {
mem::replace(&mut self.stripped_mod, true)
}
// If the impl is from a masked crate or references something from a
// masked crate then remove it completely.
- if let clean::ImplItem(ref i) = item.kind {
+ if let clean::ImplItem(ref i) = *item.kind {
if self.masked_crates.contains(&item.def_id.krate)
|| i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
|| i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
// Propagate a trait method's documentation to all implementors of the
// trait.
- if let clean::TraitItem(ref t) = item.kind {
+ if let clean::TraitItem(ref t) = *item.kind {
self.traits.entry(item.def_id).or_insert_with(|| t.clone());
}
// Collect all the implementors of traits.
- if let clean::ImplItem(ref i) = item.kind {
+ if let clean::ImplItem(ref i) = *item.kind {
if let Some(did) = i.trait_.def_id() {
if i.blanket_impl.is_none() {
self.implementors
// Index this method for searching later on.
if let Some(ref s) = item.name {
- let (parent, is_inherent_impl_item) = match item.kind {
+ let (parent, is_inherent_impl_item) = match *item.kind {
clean::StrippedItem(..) => ((None, None), false),
clean::AssocConstItem(..) | clean::TypedefItem(_, true)
if self.parent_is_trait_impl =>
_ => false,
};
- match item.kind {
+ match *item.kind {
clean::StructItem(..)
| clean::EnumItem(..)
| clean::TypedefItem(..)
// Maintain the parent stack
let orig_parent_is_trait_impl = self.parent_is_trait_impl;
- let parent_pushed = match item.kind {
+ let parent_pushed = match *item.kind {
clean::TraitItem(..)
| clean::EnumItem(..)
| clean::ForeignTypeItem
// Once we've recursively found all the generics, hoard off all the
// implementations elsewhere.
let item = self.fold_item_recur(item);
- let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = item {
+ let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
// Figure out the id of this impl. This may map to a
// primitive rather than always to a struct/enum.
// Note: matching twice to restrict the lifetime of the `i` borrow.
let mut dids = FxHashSet::default();
- if let clean::Item { kind: clean::ImplItem(ref i), .. } = item {
- match i.for_ {
- clean::ResolvedPath { did, .. }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
- dids.insert(did);
- }
- ref t => {
- let did = t
- .primitive_type()
- .and_then(|t| self.primitive_locations.get(&t).cloned());
+ match i.for_ {
+ clean::ResolvedPath { did, .. }
+ | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
+ dids.insert(did);
+ }
+ ref t => {
+ let did =
+ t.primitive_type().and_then(|t| self.primitive_locations.get(&t).cloned());
- if let Some(did) = did {
- dids.insert(did);
- }
+ if let Some(did) = did {
+ dids.insert(did);
}
}
+ }
- if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
- for bound in generics {
- if let Some(did) = bound.def_id() {
- dids.insert(did);
- }
+ if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
+ for bound in generics {
+ if let Some(did) = bound.def_id() {
+ dids.insert(did);
}
}
- } else {
- unreachable!()
- };
+ }
let impl_item = Impl { impl_item: item };
if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
for did in dids {
impl<'a> From<&'a clean::Item> for ItemType {
fn from(item: &'a clean::Item) -> ItemType {
- let kind = match item.kind {
+ let kind = match *item.kind {
clean::StrippedItem(box ref item) => item,
ref kind => kind,
};
impl Impl {
crate fn inner_impl(&self) -> &clean::Impl {
- match self.impl_item.kind {
+ match *self.impl_item.kind {
clean::ImplItem(ref impl_) => impl_,
_ => panic!("non-impl item found in impl"),
}
}
cx.mod_item_in(&item, &name, &cache)?;
- let module = match item.kind {
+ let module = match *item.kind {
clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
_ => unreachable!(),
};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
+use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_target::spec::abi::Abi;
}
impl clean::Visibility {
- crate fn print_with_space(&self) -> impl fmt::Display + '_ {
+ crate fn print_with_space<'tcx>(self, tcx: TyCtxt<'tcx>) -> impl fmt::Display + 'tcx {
use rustc_span::symbol::kw;
- display_fn(move |f| match *self {
+ display_fn(move |f| match self {
clean::Public => f.write_str("pub "),
clean::Inherited => Ok(()),
- // If this is `pub(crate)`, `path` will be empty.
- clean::Visibility::Restricted(did, _) if did.index == CRATE_DEF_INDEX => {
+ clean::Visibility::Restricted(did) if did.index == CRATE_DEF_INDEX => {
write!(f, "pub(crate) ")
}
- clean::Visibility::Restricted(did, ref path) => {
+ clean::Visibility::Restricted(did) => {
f.write_str("pub(")?;
+ let path = tcx.def_path(did);
debug!("path={:?}", path);
let first_name =
path.data[0].data.get_opt_name().expect("modules are always named");
use std::iter::Peekable;
use rustc_lexer::{LiteralKind, TokenKind};
-use rustc_span::symbol::Ident;
+use rustc_span::edition::Edition;
+use rustc_span::symbol::Symbol;
use rustc_span::with_default_session_globals;
/// Highlights `src`, returning the HTML output.
src: String,
class: Option<&str>,
playground_button: Option<&str>,
- tooltip: Option<(&str, &str)>,
+ tooltip: Option<(Option<Edition>, &str)>,
+ edition: Edition,
) -> String {
debug!("highlighting: ================\n{}\n==============", src);
let mut out = String::with_capacity(src.len());
- if let Some((tooltip, class)) = tooltip {
+ if let Some((edition_info, class)) = tooltip {
write!(
out,
- "<div class='information'><div class='tooltip {}'>ⓘ<span \
- class='tooltiptext'>{}</span></div></div>",
- class, tooltip
+ "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>",
+ class,
+ if let Some(edition_info) = edition_info {
+ format!(" data-edition=\"{}\"", edition_info)
+ } else {
+ String::new()
+ },
)
.unwrap();
}
write_header(&mut out, class);
- write_code(&mut out, &src);
+ write_code(&mut out, &src, edition);
write_footer(&mut out, playground_button);
out
.unwrap()
}
-fn write_code(out: &mut String, src: &str) {
+fn write_code(out: &mut String, src: &str, edition: Edition) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n");
- Classifier::new(&src).highlight(&mut |highlight| {
+ Classifier::new(&src, edition).highlight(&mut |highlight| {
match highlight {
Highlight::Token { text, class } => string(out, Escape(text), class),
Highlight::EnterSpan { class } => enter_span(out, class),
in_attribute: bool,
in_macro: bool,
in_macro_nonterminal: bool,
+ edition: Edition,
}
impl<'a> Classifier<'a> {
- fn new(src: &str) -> Classifier<'_> {
+ fn new(src: &str, edition: Edition) -> Classifier<'_> {
let tokens = TokenIter { src }.peekable();
- Classifier { tokens, in_attribute: false, in_macro: false, in_macro_nonterminal: false }
+ Classifier {
+ tokens,
+ in_attribute: false,
+ in_macro: false,
+ in_macro_nonterminal: false,
+ edition,
+ }
}
/// Exhausts the `Classifier` writing the output into `sink`.
"Option" | "Result" => Class::PreludeTy,
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
// Keywords are also included in the identifier set.
- _ if Ident::from_str(text).is_reserved() => Class::KeyWord,
+ _ if Symbol::intern(text).is_reserved(|| self.edition) => Class::KeyWord,
_ if self.in_macro_nonterminal => {
self.in_macro_nonterminal = false;
Class::MacroNonTerminal
use super::write_code;
use expect_test::expect_file;
+use rustc_span::edition::Edition;
const STYLE: &str = r#"
<style>
let src = include_str!("fixtures/sample.rs");
let html = {
let mut out = String::new();
- write_code(&mut out, src);
+ write_code(&mut out, src, Edition::Edition2018);
format!("{}<pre><code>{}</code></pre>\n", STYLE, out)
};
expect_file!["fixtures/sample.html"].assert_eq(&html);
println!(\"foo\");\r\n\
}\r\n";
let mut html = String::new();
- write_code(&mut html, src);
+ write_code(&mut html, src, Edition::Edition2018);
expect_file!["fixtures/dos_line.html"].assert_eq(&html);
}
.join("\n");
let krate = krate.as_ref().map(|s| &**s);
let (test, _, _) =
- doctest::make_test(&test, krate, false, &Default::default(), edition);
+ doctest::make_test(&test, krate, false, &Default::default(), edition, None);
let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" };
let edition_string = format!("&edition={}", edition);
});
let tooltip = if ignore != Ignore::None {
- Some(("This example is not tested".to_owned(), "ignore"))
+ Some((None, "ignore"))
} else if compile_fail {
- Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
+ Some((None, "compile_fail"))
} else if should_panic {
- Some(("This example panics".to_owned(), "should_panic"))
+ Some((None, "should_panic"))
} else if explicit_edition {
- Some((format!("This code runs with edition {}", edition), "edition"))
+ Some((Some(edition), "edition"))
} else {
None
};
- if let Some((s1, s2)) = tooltip {
- s.push_str(&highlight::render_with_highlighting(
- text,
- Some(&format!(
- "rust-example-rendered{}",
- if ignore != Ignore::None {
- " ignore"
- } else if compile_fail {
- " compile_fail"
- } else if should_panic {
- " should_panic"
- } else if explicit_edition {
- " edition "
- } else {
- ""
- }
- )),
- playground_button.as_deref(),
- Some((s1.as_str(), s2)),
- ));
- Some(Event::Html(s.into()))
- } else {
- s.push_str(&highlight::render_with_highlighting(
- text,
- Some(&format!(
- "rust-example-rendered{}",
- if ignore != Ignore::None {
- " ignore"
- } else if compile_fail {
- " compile_fail"
- } else if should_panic {
- " should_panic"
- } else if explicit_edition {
- " edition "
- } else {
- ""
- }
- )),
- playground_button.as_deref(),
- None,
- ));
- Some(Event::Html(s.into()))
- }
+ s.push_str(&highlight::render_with_highlighting(
+ text,
+ Some(&format!(
+ "rust-example-rendered{}",
+ if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() }
+ )),
+ playground_button.as_deref(),
+ tooltip,
+ edition,
+ ));
+ Some(Event::Html(s.into()))
}
}
struct HeadingLinks<'a, 'b, 'ids, I> {
inner: I,
toc: Option<&'b mut TocBuilder>,
- buf: VecDeque<(Event<'a>, Range<usize>)>,
+ buf: VecDeque<Event<'a>>,
id_map: &'ids mut IdMap,
}
}
}
-impl<'a, 'b, 'ids, I: Iterator<Item = (Event<'a>, Range<usize>)>> Iterator
- for HeadingLinks<'a, 'b, 'ids, I>
-{
- type Item = (Event<'a>, Range<usize>);
+impl<'a, 'b, 'ids, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a, 'b, 'ids, I> {
+ type Item = Event<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(e) = self.buf.pop_front() {
}
let event = self.inner.next();
- if let Some((Event::Start(Tag::Heading(level)), _)) = event {
+ if let Some(Event::Start(Tag::Heading(level))) = event {
let mut id = String::new();
for event in &mut self.inner {
- match &event.0 {
+ match &event {
Event::End(Tag::Heading(..)) => break,
- Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {}
Event::Text(text) | Event::Code(text) => {
id.extend(text.chars().filter_map(slugify));
- self.buf.push_back(event);
}
- _ => self.buf.push_back(event),
+ _ => {}
+ }
+ match event {
+ Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {}
+ event => self.buf.push_back(event),
}
}
let id = self.id_map.derive(id);
if let Some(ref mut builder) = self.toc {
let mut html_header = String::new();
- html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone()));
+ html::push_html(&mut html_header, self.buf.iter().cloned());
let sec = builder.push(level as u32, html_header, id.clone());
- self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0));
+ self.buf.push_front(Event::Html(format!("{} ", sec).into()));
}
- self.buf.push_back((Event::Html(format!("</a></h{}>", level).into()), 0..0));
+ self.buf.push_back(Event::Html(format!("</a></h{}>", level).into()));
let start_tags = format!(
"<h{level} id=\"{id}\" class=\"section-header\">\
id = id,
level = level
);
- return Some((Event::Html(start_tags.into()), 0..0));
+ return Some(Event::Html(start_tags.into()));
}
event
}
}
}
-impl<'a, I: Iterator<Item = (Event<'a>, Range<usize>)>> Iterator for Footnotes<'a, I> {
- type Item = (Event<'a>, Range<usize>);
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Footnotes<'a, I> {
+ type Item = Event<'a>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.inner.next() {
- Some((Event::FootnoteReference(ref reference), range)) => {
+ Some(Event::FootnoteReference(ref reference)) => {
let entry = self.get_entry(&reference);
let reference = format!(
"<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>",
(*entry).1
);
- return Some((Event::Html(reference.into()), range));
+ return Some(Event::Html(reference.into()));
}
- Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
+ Some(Event::Start(Tag::FootnoteDefinition(def))) => {
let mut content = Vec::new();
- for (event, _) in &mut self.inner {
+ for event in &mut self.inner {
if let Event::End(Tag::FootnoteDefinition(..)) = event {
break;
}
ret.push_str("</li>");
}
ret.push_str("</ol></div>");
- return Some((Event::Html(ret.into()), 0..0));
+ return Some(Event::Html(ret.into()));
} else {
return None;
}
};
let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
- let p = p.into_offset_iter();
let mut s = String::with_capacity(md.len() * 3 / 2);
let p = HeadingLinks::new(p, None, &mut ids);
- let p = Footnotes::new(p);
- let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
+ let p = LinkReplacer::new(p, links);
let p = CodeBlocks::new(p, codes, edition, playground);
+ let p = Footnotes::new(p);
html::push_html(&mut s, p);
s
crate fn into_string(self) -> String {
let MarkdownWithToc(md, mut ids, codes, edition, playground) = self;
- let p = Parser::new_ext(md, opts()).into_offset_iter();
+ let p = Parser::new_ext(md, opts());
let mut s = String::with_capacity(md.len() * 3 / 2);
{
let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
+ let p = CodeBlocks::new(p, codes, edition, playground);
let p = Footnotes::new(p);
- let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground);
html::push_html(&mut s, p);
}
if md.is_empty() {
return String::new();
}
- let p = Parser::new_ext(md, opts()).into_offset_iter();
+ let p = Parser::new_ext(md, opts());
// Treat inline HTML as plain text.
- let p = p.map(|event| match event.0 {
- Event::Html(text) => (Event::Text(text), event.1),
+ let p = p.map(|event| match event {
+ Event::Html(text) => Event::Text(text),
_ => event,
});
let mut s = String::with_capacity(md.len() * 3 / 2);
let p = HeadingLinks::new(p, None, &mut ids);
+ let p = CodeBlocks::new(p, codes, edition, playground);
let p = Footnotes::new(p);
- let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground);
html::push_html(&mut s, p);
s
fn push(s: &mut String, text_length: &mut usize, text: &str) {
s.push_str(text);
*text_length += text.len();
- };
+ }
'outer: for event in Parser::new_ext(md, summary_opts()) {
match &event {
s
}
-crate fn markdown_links(md: &str) -> Vec<(String, Range<usize>)> {
+crate fn markdown_links(md: &str) -> Vec<(String, Option<Range<usize>>)> {
if md.is_empty() {
return vec![];
}
let mut links = vec![];
- // Used to avoid mutable borrow issues in the `push` closure
- // Probably it would be more efficient to use a `RefCell` but it doesn't seem worth the churn.
let mut shortcut_links = vec![];
- let span_for_link = |link: &str, span: Range<usize>| {
- // Pulldown includes the `[]` as well as the URL. Only highlight the relevant span.
- // NOTE: uses `rfind` in case the title and url are the same: `[Ok][Ok]`
- match md[span.clone()].rfind(link) {
- Some(start) => {
- let start = span.start + start;
- start..start + link.len()
+ {
+ let locate = |s: &str| unsafe {
+ let s_start = s.as_ptr();
+ let s_end = s_start.add(s.len());
+ let md_start = md.as_ptr();
+ let md_end = md_start.add(md.len());
+ if md_start <= s_start && s_end <= md_end {
+ let start = s_start.offset_from(md_start) as usize;
+ let end = s_end.offset_from(md_start) as usize;
+ Some(start..end)
+ } else {
+ None
+ }
+ };
+
+ let mut push = |link: BrokenLink<'_>| {
+ // FIXME: use `link.span` instead of `locate`
+ // (doing it now includes the `[]` as well as the text)
+ shortcut_links.push((link.reference.to_owned(), locate(link.reference)));
+ None
+ };
+ let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push));
+
+ // There's no need to thread an IdMap through to here because
+ // the IDs generated aren't going to be emitted anywhere.
+ let mut ids = IdMap::new();
+ let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids));
+
+ for ev in iter {
+ if let Event::Start(Tag::Link(_, dest, _)) = ev {
+ debug!("found link: {}", dest);
+ links.push(match dest {
+ CowStr::Borrowed(s) => (s.to_owned(), locate(s)),
+ s @ (CowStr::Boxed(..) | CowStr::Inlined(..)) => (s.into_string(), None),
+ });
}
- // This can happen for things other than intra-doc links, like `#1` expanded to `https://github.com/rust-lang/rust/issues/1`.
- None => span,
- }
- };
- let mut push = |link: BrokenLink<'_>| {
- let span = span_for_link(link.reference, link.span);
- shortcut_links.push((link.reference.to_owned(), span));
- None
- };
- let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push));
-
- // There's no need to thread an IdMap through to here because
- // the IDs generated aren't going to be emitted anywhere.
- let mut ids = IdMap::new();
- let iter = Footnotes::new(HeadingLinks::new(p.into_offset_iter(), None, &mut ids));
-
- for ev in iter {
- if let Event::Start(Tag::Link(_, dest, _)) = ev.0 {
- debug!("found link: {}", dest);
- let span = span_for_link(&dest, ev.1);
- links.push((dest.into_string(), span));
}
}
}
crate fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
- let (all_types, ret_types) = match item.kind {
+ let (all_types, ret_types) = match *item.kind {
clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
clean::MethodItem(ref m, _) => (&m.all_types, &m.ret_types),
clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
playground: Option<markdown::Playground>,
}
-impl Context<'_> {
+impl<'tcx> Context<'tcx> {
fn path(&self, filename: &str) -> PathBuf {
// We use splitn vs Path::extension here because we might get a filename
// like `style.min.css` and we want to process that into
self.dst.join(&filename)
}
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.shared.tcx
+ }
+
fn sess(&self) -> &Session {
&self.shared.tcx.sess
}
fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> {
let final_file = self.dst.join(&*krate.name.as_str()).join("all.html");
let settings_file = self.dst.join("settings.html");
- let crate_name = krate.name.clone();
+ let crate_name = krate.name;
let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
if !root_path.ends_with('/') {
// Render sidebar-items.js used throughout this module.
if !self.render_redirect_pages {
- let module = match item.kind {
+ let module = match *item.kind {
clean::StrippedItem(box clean::ModuleItem(ref m)) | clean::ModuleItem(ref m) => m,
_ => unreachable!(),
};
write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">");
render_stability_since_raw(
buf,
- item.stable_since().as_deref(),
- item.const_stable_since().as_deref(),
+ item.stable_since(cx.tcx()).as_deref(),
+ item.const_stable_since(cx.tcx()).as_deref(),
None,
None,
);
write!(buf, "</span>"); // out-of-band
write!(buf, "<span class=\"in-band\">");
- let name = match item.kind {
+ let name = match *item.kind {
clean::ModuleItem(ref m) => {
if m.is_crate {
"Crate "
write!(buf, "</span></h1>"); // in-band
- match item.kind {
+ match *item.kind {
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
item_function(buf, cx, item, f)
}
}
- fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering {
+ fn cmp(
+ i1: &clean::Item,
+ i2: &clean::Item,
+ idx1: usize,
+ idx2: usize,
+ tcx: TyCtxt<'_>,
+ ) -> Ordering {
let ty1 = i1.type_();
let ty2 = i2.type_();
if ty1 != ty2 {
return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2));
}
- let s1 = i1.stability.as_ref().map(|s| s.level);
- let s2 = i2.stability.as_ref().map(|s| s.level);
+ let s1 = i1.stability(tcx).as_ref().map(|s| s.level);
+ let s2 = i2.stability(tcx).as_ref().map(|s| s.level);
if let (Some(a), Some(b)) = (s1, s2) {
match (a.is_stable(), b.is_stable()) {
(true, true) | (false, false) => {}
(true, false) => return Ordering::Greater,
}
}
- let lhs = i1.name.unwrap_or(kw::Invalid).as_str();
- let rhs = i2.name.unwrap_or(kw::Invalid).as_str();
+ let lhs = i1.name.unwrap_or(kw::Empty).as_str();
+ let rhs = i2.name.unwrap_or(kw::Empty).as_str();
compare_names(&lhs, &rhs)
}
if cx.shared.sort_modules_alphabetically {
- indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
+ indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx()));
}
// This call is to remove re-export duplicates in cases such as:
//
);
}
- match myitem.kind {
+ match *myitem.kind {
clean::ExternCrateItem(ref name, ref src) => {
use crate::html::format::anchor;
Some(ref src) => write!(
w,
"<tr><td><code>{}extern crate {} as {};",
- myitem.visibility.print_with_space(),
+ myitem.visibility.print_with_space(cx.tcx()),
anchor(myitem.def_id, &*src.as_str()),
name
),
None => write!(
w,
"<tr><td><code>{}extern crate {};",
- myitem.visibility.print_with_space(),
+ myitem.visibility.print_with_space(cx.tcx()),
anchor(myitem.def_id, &*name.as_str())
),
}
write!(
w,
"<tr><td><code>{}{}</code></td></tr>",
- myitem.visibility.print_with_space(),
+ myitem.visibility.print_with_space(cx.tcx()),
import.print()
);
}
continue;
}
- let unsafety_flag = match myitem.kind {
+ let unsafety_flag = match *myitem.kind {
clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
if func.header.unsafety == hir::Unsafety::Unsafe =>
{
_ => "",
};
- let stab = myitem.stability_class();
+ let stab = myitem.stability_class(cx.tcx());
let add = if stab.is_some() { " " } else { "" };
let doc_value = myitem.doc_value().unwrap_or("");
<td class=\"docblock-short\">{stab_tags}{docs}</td>\
</tr>",
name = *myitem.name.as_ref().unwrap(),
- stab_tags = extra_info_tags(myitem, item),
+ stab_tags = extra_info_tags(myitem, item, cx.tcx()),
docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(),
class = myitem.type_(),
add = add,
/// Render the stability, deprecation and portability tags that are displayed in the item's summary
/// at the module level.
-fn extra_info_tags(item: &clean::Item, parent: &clean::Item) -> String {
+fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> String {
let mut tags = String::new();
fn tag_html(class: &str, title: &str, contents: &str) -> String {
}
// The trailing space after each tag is to space it properly against the rest of the docs.
- if let Some(depr) = &item.deprecation {
+ if let Some(depr) = &item.deprecation(tcx) {
let mut message = "Deprecated";
if !stability::deprecation_in_effect(
depr.is_since_rustc_version,
// The "rustc_private" crates are permanently unstable so it makes no sense
// to render "unstable" everywhere.
- if item.stability.as_ref().map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
+ if item
+ .stability(tcx)
+ .as_ref()
+ .map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
== Some(true)
{
tags += &tag_html("unstable", "", "Experimental");
let error_codes = cx.shared.codes;
if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) =
- item.deprecation
+ item.deprecation(cx.tcx())
{
// We display deprecation messages for #[deprecated] and #[rustc_deprecated]
// but only display the future-deprecation messages for #[rustc_deprecated].
// Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
// Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
- .stability
+ .stability(cx.tcx())
.as_ref()
.filter(|stab| stab.feature != sym::rustc_private)
.map(|stab| (stab.level, stab.feature))
write!(
w,
"{vis}const {name}: {typ}",
- vis = it.visibility.print_with_space(),
+ vis = it.visibility.print_with_space(cx.tcx()),
name = it.name.as_ref().unwrap(),
typ = c.type_.print(),
);
write!(
w,
"{vis}static {mutability}{name}: {typ}</pre>",
- vis = it.visibility.print_with_space(),
+ vis = it.visibility.print_with_space(cx.tcx()),
mutability = s.mutability.print_with_space(),
name = it.name.as_ref().unwrap(),
typ = s.type_.print()
fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
let header_len = format!(
"{}{}{}{}{:#}fn {}{:#}",
- it.visibility.print_with_space(),
+ it.visibility.print_with_space(cx.tcx()),
f.header.constness.print_with_space(),
f.header.asyncness.print_with_space(),
f.header.unsafety.print_with_space(),
w,
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
{name}{generics}{decl}{spotlight}{where_clause}</pre>",
- vis = it.visibility.print_with_space(),
+ vis = it.visibility.print_with_space(cx.tcx()),
constness = f.header.constness.print_with_space(),
asyncness = f.header.asyncness.print_with_space(),
unsafety = f.header.unsafety.print_with_space(),
parent,
AssocItemLink::Anchor(None),
RenderMode::Normal,
- implementor.impl_item.stable_since().as_deref(),
- implementor.impl_item.const_stable_since().as_deref(),
+ implementor.impl_item.stable_since(cx.tcx()).as_deref(),
+ implementor.impl_item.const_stable_since(cx.tcx()).as_deref(),
false,
Some(use_absolute),
false,
containing_item,
assoc_link,
RenderMode::Normal,
- containing_item.stable_since().as_deref(),
- containing_item.const_stable_since().as_deref(),
+ containing_item.stable_since(cx.tcx()).as_deref(),
+ containing_item.const_stable_since(cx.tcx()).as_deref(),
true,
None,
false,
write!(
w,
"{}{}{}trait {}{}{}",
- it.visibility.print_with_space(),
+ it.visibility.print_with_space(cx.tcx()),
t.unsafety.print_with_space(),
if t.is_auto { "auto " } else { "" },
it.name.as_ref().unwrap(),
// FIXME: we should be using a derived_id for the Anchors here
write!(w, "{{\n");
for t in &types {
- render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+ render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
write!(w, ";\n");
}
if !types.is_empty() && !consts.is_empty() {
w.write_str("\n");
}
for t in &consts {
- render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
+ render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
write!(w, ";\n");
}
if !consts.is_empty() && !required.is_empty() {
w.write_str("\n");
}
for (pos, m) in required.iter().enumerate() {
- render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
+ render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
write!(w, ";\n");
if pos < required.len() - 1 {
w.write_str("\n");
}
for (pos, m) in provided.iter().enumerate() {
- render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
- match m.kind {
+ render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ match *m.kind {
clean::MethodItem(ref inner, _)
if !inner.generics.where_predicates.is_empty() =>
{
let item_type = m.type_();
let id = cx.derive_id(format!("{}.{}", item_type, name));
write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,);
- render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
+ render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
write!(w, "</code>");
- render_stability_since(w, m, t);
+ render_stability_since(w, m, t, cx.tcx());
write_srclink(cx, m, w, cache);
write!(w, "</h3>");
document(w, cx, m, Some(t));
it,
assoc_link,
RenderMode::Normal,
- implementor.impl_item.stable_since().as_deref(),
- implementor.impl_item.const_stable_since().as_deref(),
+ implementor.impl_item.stable_since(cx.tcx()).as_deref(),
+ implementor.impl_item.const_stable_since(cx.tcx()).as_deref(),
false,
None,
true,
_default: Option<&String>,
link: AssocItemLink<'_>,
extra: &str,
+ cx: &Context<'_>,
) {
write!(
w,
"{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}",
extra,
- it.visibility.print_with_space(),
+ it.visibility.print_with_space(cx.tcx()),
naive_assoc_href(it, link),
it.name.as_ref().unwrap(),
ty.print()
}
}
-fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) {
+fn render_stability_since(
+ w: &mut Buffer,
+ item: &clean::Item,
+ containing_item: &clean::Item,
+ tcx: TyCtxt<'_>,
+) {
render_stability_since_raw(
w,
- item.stable_since().as_deref(),
- item.const_stable_since().as_deref(),
- containing_item.stable_since().as_deref(),
- containing_item.const_stable_since().as_deref(),
+ item.stable_since(tcx).as_deref(),
+ item.const_stable_since(tcx).as_deref(),
+ containing_item.stable_since(tcx).as_deref(),
+ containing_item.const_stable_since(tcx).as_deref(),
)
}
item: &clean::Item,
link: AssocItemLink<'_>,
parent: ItemType,
+ cx: &Context<'_>,
) {
fn method(
w: &mut Buffer,
d: &clean::FnDecl,
link: AssocItemLink<'_>,
parent: ItemType,
+ cx: &Context<'_>,
) {
let name = meth.name.as_ref().unwrap();
let anchor = format!("#{}.{}", meth.type_(), name);
};
let mut header_len = format!(
"{}{}{}{}{}{:#}fn {}{:#}",
- meth.visibility.print_with_space(),
+ meth.visibility.print_with_space(cx.tcx()),
header.constness.print_with_space(),
header.asyncness.print_with_space(),
header.unsafety.print_with_space(),
"{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
{generics}{decl}{spotlight}{where_clause}",
if parent == ItemType::Trait { " " } else { "" },
- meth.visibility.print_with_space(),
+ meth.visibility.print_with_space(cx.tcx()),
header.constness.print_with_space(),
header.asyncness.print_with_space(),
header.unsafety.print_with_space(),
where_clause = WhereClause { gens: g, indent, end_newline }
)
}
- match item.kind {
+ match *item.kind {
clean::StrippedItem(..) => {}
- clean::TyMethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent),
+ clean::TyMethodItem(ref m) => {
+ method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
+ }
clean::MethodItem(ref m, _) => {
- method(w, item, m.header, &m.generics, &m.decl, link, parent)
+ method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
}
clean::AssocConstItem(ref ty, ref default) => assoc_const(
w,
default.as_ref(),
link,
if parent == ItemType::Trait { " " } else { "" },
+ cx,
),
clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
w,
wrap_into_docblock(w, |w| {
write!(w, "<pre class=\"rust struct\">");
render_attributes(w, it, true);
- render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true);
+ render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
write!(w, "</pre>")
});
let mut fields = s
.fields
.iter()
- .filter_map(|f| match f.kind {
+ .filter_map(|f| match *f.kind {
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
})
wrap_into_docblock(w, |w| {
write!(w, "<pre class=\"rust union\">");
render_attributes(w, it, true);
- render_union(w, it, Some(&s.generics), &s.fields, "", true);
+ render_union(w, it, Some(&s.generics), &s.fields, "", true, cx);
write!(w, "</pre>")
});
let mut fields = s
.fields
.iter()
- .filter_map(|f| match f.kind {
+ .filter_map(|f| match *f.kind {
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
})
shortty = ItemType::StructField,
ty = ty.print()
);
- if let Some(stability_class) = field.stability_class() {
+ if let Some(stability_class) = field.stability_class(cx.tcx()) {
write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
}
document(w, cx, field, Some(it));
write!(
w,
"{}enum {}{}{}",
- it.visibility.print_with_space(),
+ it.visibility.print_with_space(cx.tcx()),
it.name.as_ref().unwrap(),
e.generics.print(),
WhereClause { gens: &e.generics, indent: 0, end_newline: true }
for v in &e.variants {
write!(w, " ");
let name = v.name.as_ref().unwrap();
- match v.kind {
+ match *v.kind {
clean::VariantItem(ref var) => match var.kind {
clean::VariantKind::CLike => write!(w, "{}", name),
clean::VariantKind::Tuple(ref tys) => {
write!(w, ")");
}
clean::VariantKind::Struct(ref s) => {
- render_struct(w, v, None, s.struct_type, &s.fields, " ", false);
+ render_struct(w, v, None, s.struct_type, &s.fields, " ", false, cx);
}
},
_ => unreachable!(),
id = id,
name = variant.name.as_ref().unwrap()
);
- if let clean::VariantItem(ref var) = variant.kind {
+ if let clean::VariantItem(ref var) = *variant.kind {
if let clean::VariantKind::Tuple(ref tys) = var.kind {
write!(w, "(");
for (i, ty) in tys.iter().enumerate() {
document_non_exhaustive(w, variant);
use crate::clean::{Variant, VariantKind};
- if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = variant.kind {
+ if let clean::VariantItem(Variant { kind: VariantKind::Struct(ref s) }) = *variant.kind
+ {
let variant_id = cx.derive_id(format!(
"{}.{}.fields",
ItemType::Variant,
);
for field in &s.fields {
use crate::clean::StructFieldItem;
- if let StructFieldItem(ref ty) = field.kind {
+ if let StructFieldItem(ref ty) = *field.kind {
let id = cx.derive_id(format!(
"variant.{}.field.{}",
variant.name.as_ref().unwrap(),
}
write!(w, "</div></div>");
}
- render_stability_since(w, variant, it);
+ render_stability_since(w, variant, it, cx.tcx());
}
}
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
fields: &[clean::Item],
tab: &str,
structhead: bool,
+ cx: &Context<'_>,
) {
write!(
w,
"{}{}{}",
- it.visibility.print_with_space(),
+ it.visibility.print_with_space(cx.tcx()),
if structhead { "struct " } else { "" },
it.name.as_ref().unwrap()
);
let mut has_visible_fields = false;
write!(w, " {{");
for field in fields {
- if let clean::StructFieldItem(ref ty) = field.kind {
+ if let clean::StructFieldItem(ref ty) = *field.kind {
write!(
w,
"\n{} {}{}: {},",
tab,
- field.visibility.print_with_space(),
+ field.visibility.print_with_space(cx.tcx()),
field.name.as_ref().unwrap(),
ty.print()
);
if i > 0 {
write!(w, ", ");
}
- match field.kind {
+ match *field.kind {
clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
clean::StructFieldItem(ref ty) => {
- write!(w, "{}{}", field.visibility.print_with_space(), ty.print())
+ write!(w, "{}{}", field.visibility.print_with_space(cx.tcx()), ty.print())
}
_ => unreachable!(),
}
fields: &[clean::Item],
tab: &str,
structhead: bool,
+ cx: &Context<'_>,
) {
write!(
w,
"{}{}{}",
- it.visibility.print_with_space(),
+ it.visibility.print_with_space(cx.tcx()),
if structhead { "union " } else { "" },
it.name.as_ref().unwrap()
);
write!(w, " {{\n{}", tab);
for field in fields {
- if let clean::StructFieldItem(ref ty) = field.kind {
+ if let clean::StructFieldItem(ref ty) = *field.kind {
write!(
w,
" {}{}: {},\n{}",
- field.visibility.print_with_space(),
+ field.visibility.print_with_space(cx.tcx()),
field.name.as_ref().unwrap(),
ty.print(),
tab
}
impl<'a> AssocItemLink<'a> {
- fn anchor(&self, id: &'a String) -> Self {
+ fn anchor(&self, id: &'a str) -> Self {
match *self {
AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
ref other => *other,
containing_item,
AssocItemLink::Anchor(None),
render_mode,
- containing_item.stable_since().as_deref(),
- containing_item.const_stable_since().as_deref(),
+ containing_item.stable_since(cx.tcx()).as_deref(),
+ containing_item.const_stable_since(cx.tcx()).as_deref(),
true,
None,
false,
.inner_impl()
.items
.iter()
- .find_map(|item| match item.kind {
+ .find_map(|item| match *item.kind {
clean::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.type_, &t.type_),
}
fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
- let self_type_opt = match item.kind {
+ let self_type_opt = match *item.kind {
clean::MethodItem(ref method, _) => method.decl.self_type(),
clean::TyMethodItem(ref method) => method.decl.self_type(),
_ => None,
));
let t_did = impl_.trait_.def_id().unwrap();
for it in &impl_.items {
- if let clean::TypedefItem(ref tydef, _) = it.kind {
+ if let clean::TypedefItem(ref tydef, _) = *it.kind {
out.push_str("<span class=\"where fmt-newline\"> ");
assoc_type(
&mut out,
fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute);
if show_def_docs {
for it in &i.inner_impl().items {
- if let clean::TypedefItem(ref tydef, _) = it.kind {
+ if let clean::TypedefItem(ref tydef, _) = *it.kind {
write!(w, "<span class=\"where fmt-newline\"> ");
assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "");
write!(w, ";</span>");
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
render_stability_since_raw(
w,
- i.impl_item.stable_since().as_deref(),
- i.impl_item.const_stable_since().as_deref(),
+ i.impl_item.stable_since(cx.tcx()).as_deref(),
+ i.impl_item.const_stable_since(cx.tcx()).as_deref(),
outer_version,
outer_const_version,
);
} else {
(true, " hidden")
};
- match item.kind {
+ match *item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => {
// Only render when the method is not static or we allow static methods
if render_method_item {
let id = cx.derive_id(format!("{}.{}", item_type, name));
write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, extra_class);
write!(w, "<code>");
- render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
+ render_assoc_item(w, item, link.anchor(&id), ItemType::Impl, cx);
write!(w, "</code>");
render_stability_since_raw(
w,
- item.stable_since().as_deref(),
- item.const_stable_since().as_deref(),
+ item.stable_since(cx.tcx()).as_deref(),
+ item.const_stable_since(cx.tcx()).as_deref(),
outer_version,
outer_const_version,
);
clean::AssocConstItem(ref ty, ref default) => {
let id = cx.derive_id(format!("{}.{}", item_type, name));
write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
- assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "");
+ assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "", cx);
write!(w, "</code>");
render_stability_since_raw(
w,
- item.stable_since().as_deref(),
- item.const_stable_since().as_deref(),
+ item.stable_since(cx.tcx()).as_deref(),
+ item.const_stable_since(cx.tcx()).as_deref(),
outer_version,
outer_const_version,
);
cache: &Cache,
) {
for trait_item in &t.items {
- let n = trait_item.name.clone();
+ let n = trait_item.name;
if i.items.iter().any(|m| m.name == n) {
continue;
}
write!(
w,
" {}type {};\n}}</pre>",
- it.visibility.print_with_space(),
+ it.visibility.print_with_space(cx.tcx()),
it.name.as_ref().unwrap(),
);
write!(
buffer,
"<p class=\"location\">{}{}</p>",
- match it.kind {
+ match *it.kind {
clean::StructItem(..) => "Struct ",
clean::TraitItem(..) => "Trait ",
clean::PrimitiveItem(..) => "Primitive Type ",
it.name.as_ref().expect("crates always have a name")
);
}
- match it.kind {
+ match *it.kind {
clean::StructItem(ref s) => sidebar_struct(buffer, it, s),
clean::TraitItem(ref t) => sidebar_trait(buffer, it, t),
clean::PrimitiveItem(_) => sidebar_primitive(buffer, it),
ty: \"{ty}\", \
relpath: \"{path}\"\
}};</script>",
- name = it.name.unwrap_or(kw::Invalid),
+ name = it.name.unwrap_or(kw::Empty),
ty = it.type_(),
path = relpath
);
.find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
{
if let Some((target, real_target)) =
- impl_.inner_impl().items.iter().find_map(|item| match item.kind {
+ impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
clean::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.type_, &t.type_),
}
fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
- match item.kind {
+ match *item.kind {
clean::ItemKind::ImplItem(ref i) => {
if let Some(ref trait_) = i.trait_ {
Some((
fn get_struct_fields_name(fields: &[clean::Item]) -> String {
let mut fields = fields
.iter()
- .filter(|f| if let clean::StructFieldItem(..) = f.kind { true } else { false })
+ .filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
.filter_map(|f| match f.name {
Some(ref name) => {
Some(format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))
Some("macro"),
None,
None,
+ it.source.span().edition(),
))
});
document(w, cx, it, None)
use crate::html::render::{SharedContext, BASIC_KEYWORDS};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_session::Session;
+use rustc_span::edition::Edition;
use rustc_span::source_map::FileName;
use std::ffi::OsStr;
use std::fs;
&self.scx.layout,
&page,
"",
- |buf: &mut _| print_src(buf, contents),
+ |buf: &mut _| print_src(buf, contents, self.scx.edition),
&self.scx.style_files,
);
self.scx.fs.write(&cur, v.as_bytes())?;
/// Wrapper struct to render the source code of a file. This will do things like
/// adding line numbers to the left-hand side.
-fn print_src(buf: &mut Buffer, s: String) {
+fn print_src(buf: &mut Buffer, s: String, edition: Edition) {
let lines = s.lines().count();
let mut cols = 0;
let mut tmp = lines;
write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols);
}
write!(buf, "</pre>");
- write!(buf, "{}", highlight::render_with_highlighting(s, None, None, None));
+ write!(buf, "{}", highlight::render_with_highlighting(s, None, None, None, edition));
}
h1, h2, h3, h4,
.sidebar, a.source, .search-input, .content table td:first-child > a,
.collapse-toggle, div.item-list .out-of-band,
-#source-sidebar, #sidebar-toggle {
+#source-sidebar, #sidebar-toggle,
+/* This selector is for the items listed in the "all items" page. */
+#main > ul.docblock > li > a {
font-family: "Fira Sans", sans-serif;
}
cursor: pointer;
}
-.tooltip .tooltiptext {
- width: 120px;
+.tooltip::after {
display: none;
text-align: center;
padding: 5px 3px 3px 3px;
border-radius: 6px;
margin-left: 5px;
- top: -5px;
- left: 105%;
- z-index: 10;
font-size: 16px;
}
-.tooltip .tooltiptext::after {
+.tooltip.ignore::after {
+ content: "This example is not tested";
+}
+.tooltip.compile_fail::after {
+ content: "This example deliberately fails to compile";
+}
+.tooltip.should_panic::after {
+ content: "This example panics";
+}
+.tooltip.edition::after {
+ content: "This code runs with edition " attr(data-edition);
+}
+
+.tooltip::before {
content: " ";
position: absolute;
top: 50%;
margin-top: -5px;
border-width: 5px;
border-style: solid;
+ display: none;
}
-.tooltip:hover .tooltiptext {
+.tooltip:hover::before, .tooltip:hover::after {
display: inline;
}
color: #39AFD7;
}
-.tooltip .tooltiptext {
+.tooltip::after {
background-color: #314559;
color: #c5c5c5;
border: 1px solid #5c6773;
}
-.tooltip .tooltiptext::after {
+.tooltip::before {
border-color: transparent #314559 transparent transparent;
}
color: #0089ff;
}
-.tooltip .tooltiptext {
+.tooltip::after {
background-color: #000;
color: #fff;
border-color: #000;
}
-.tooltip .tooltiptext::after {
+.tooltip::before {
border-color: transparent black transparent transparent;
}
color: #0089ff;
}
-.tooltip .tooltiptext {
+.tooltip::after {
background-color: #000;
color: #fff;
}
-.tooltip .tooltiptext::after {
+.tooltip::before {
border-color: transparent black transparent transparent;
}
impl JsonRenderer<'_> {
pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
let item_type = ItemType::from(&item);
- let clean::Item {
- source,
- name,
- attrs,
- kind,
- visibility,
- def_id,
- stability: _,
- const_stability: _,
- deprecation,
- } = item;
- match kind {
+ let deprecation = item.deprecation(self.tcx);
+ let clean::Item { source, name, attrs, kind, visibility, def_id } = item;
+ match *kind {
clean::StrippedItem(_) => None,
- _ => Some(Item {
+ kind => Some(Item {
id: def_id.into(),
crate_id: def_id.krate.as_u32(),
name: name.map(|sym| sym.to_string()),
source: self.convert_span(source),
- visibility: visibility.into(),
+ visibility: self.convert_visibility(visibility),
docs: attrs.collapsed_doc_value().unwrap_or_default(),
links: attrs
.links
_ => None,
}
}
-}
-
-impl From<rustc_attr::Deprecation> for Deprecation {
- fn from(deprecation: rustc_attr::Deprecation) -> Self {
- #[rustfmt::skip]
- let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
- Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
- }
-}
-impl From<clean::Visibility> for Visibility {
- fn from(v: clean::Visibility) -> Self {
+ fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
use clean::Visibility::*;
match v {
Public => Visibility::Public,
Inherited => Visibility::Default,
- Restricted(did, _) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
- Restricted(did, path) => Visibility::Restricted {
+ Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
+ Restricted(did) => Visibility::Restricted {
parent: did.into(),
- path: path.to_string_no_crate_verbose(),
+ path: self.tcx.def_path(did).to_string_no_crate_verbose(),
},
}
}
}
+impl From<rustc_attr::Deprecation> for Deprecation {
+ fn from(deprecation: rustc_attr::Deprecation) -> Self {
+ #[rustfmt::skip]
+ let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
+ Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
+ }
+}
+
impl From<clean::GenericArgs> for GenericArgs {
fn from(args: clean::GenericArgs) -> Self {
use clean::GenericArgs::*;
cache: &Cache,
) -> Result<(), Error> {
use clean::types::ItemKind::*;
- if let ModuleItem(m) = &item.kind {
+ if let ModuleItem(m) = &*item.kind {
for item in &m.items {
- match &item.kind {
+ match &*item.kind {
// These don't have names so they don't get added to the output by default
ImportItem(_) => self.item(item.clone(), cache).unwrap(),
ExternCrateItem(_, _) => self.item(item.clone(), cache).unwrap(),
#![feature(type_ascription)]
#![feature(split_inclusive)]
#![feature(str_split_once)]
+#![feature(iter_intersperse)]
#![recursion_limit = "256"]
#[macro_use]
"sort modules by where they appear in the program, rather than alphabetically",
)
}),
- unstable("default-theme", |o| {
+ stable("default-theme", |o| {
o.optopt(
"",
"default-theme",
"Set the default theme. THEME should be the theme name, generally lowercase. \
If an unknown default theme is specified, the builtin default is used. \
- The set of themes, and the rustdoc built-in default is not stable.",
+ The set of themes, and the rustdoc built-in default, are not stable.",
"THEME",
)
}),
use crate::passes::doc_test_lints::{should_have_doc_example, Tests};
use crate::passes::Pass;
use rustc_lint::builtin::MISSING_DOCS;
-use rustc_middle::lint::LintSource;
+use rustc_middle::lint::LintLevelSource;
use rustc_session::lint;
use rustc_span::symbol::sym;
use rustc_span::FileName;
impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
- match i.kind {
+ match *i.kind {
_ if !i.def_id.is_local() => {
// non-local items are skipped because they can be out of the users control,
// especially in the case of trait impls, which rustdoc eagerly inlines
// `missing_docs` is allow-by-default, so don't treat this as ignoring the item
// unless the user had an explicit `allow`
let should_have_docs =
- level != lint::Level::Allow || matches!(source, LintSource::Default);
+ level != lint::Level::Allow || matches!(source, LintLevelSource::Default);
debug!("counting {:?} {:?} in {}", i.type_(), i.name, filename);
self.items.entry(filename).or_default().count_item(
has_docs,
use rustc_hir::def::{
DefKind,
Namespace::{self, *},
- PerNS, Res,
+ PerNS,
};
use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
use rustc_resolve::ParentScope;
use rustc_session::lint::{
builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS},
Lint,
};
use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::sym;
use rustc_span::symbol::Ident;
use rustc_span::symbol::Symbol;
use rustc_span::DUMMY_SP;
use std::borrow::Cow;
use std::cell::Cell;
+use std::convert::{TryFrom, TryInto};
use std::mem;
use std::ops::Range;
}
}
+#[derive(Copy, Clone, Debug, Hash)]
+enum Res {
+ Def(DefKind, DefId),
+ Primitive(PrimitiveType),
+}
+
+type ResolveRes = rustc_hir::def::Res<rustc_ast::NodeId>;
+
+impl Res {
+ fn descr(self) -> &'static str {
+ match self {
+ Res::Def(kind, id) => ResolveRes::Def(kind, id).descr(),
+ Res::Primitive(_) => "builtin type",
+ }
+ }
+
+ fn article(self) -> &'static str {
+ match self {
+ Res::Def(kind, id) => ResolveRes::Def(kind, id).article(),
+ Res::Primitive(_) => "a",
+ }
+ }
+
+ fn name(self, tcx: ty::TyCtxt<'_>) -> String {
+ match self {
+ Res::Def(_, id) => tcx.item_name(id).to_string(),
+ Res::Primitive(prim) => prim.as_str().to_string(),
+ }
+ }
+
+ fn def_id(self) -> DefId {
+ self.opt_def_id().expect("called def_id() on a primitive")
+ }
+
+ fn opt_def_id(self) -> Option<DefId> {
+ match self {
+ Res::Def(_, id) => Some(id),
+ Res::Primitive(_) => None,
+ }
+ }
+
+ fn as_hir_res(self) -> Option<rustc_hir::def::Res> {
+ match self {
+ Res::Def(kind, id) => Some(rustc_hir::def::Res::Def(kind, id)),
+ // FIXME: maybe this should handle the subset of PrimitiveType that fits into hir::PrimTy?
+ Res::Primitive(_) => None,
+ }
+ }
+}
+
+impl TryFrom<ResolveRes> for Res {
+ type Error = ();
+
+ fn try_from(res: ResolveRes) -> Result<Self, ()> {
+ use rustc_hir::def::Res::*;
+ match res {
+ Def(kind, id) => Ok(Res::Def(kind, id)),
+ PrimTy(prim) => Ok(Res::Primitive(PrimitiveType::from_hir(prim))),
+ // e.g. `#[derive]`
+ NonMacroAttr(..) | Err => Result::Err(()),
+ other => bug!("unrecognized res {:?}", other),
+ }
+ }
+}
+
#[derive(Debug)]
/// A link failed to resolve.
enum ResolutionFailure<'a> {
item: &'a Item,
dox: &'a str,
ori_link: &'a str,
- link_range: Range<usize>,
+ link_range: Option<Range<usize>>,
}
#[derive(Clone, Debug, Hash)]
.enter_resolver(|resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
})
- .map(|(_, res)| res)
- .unwrap_or(Res::Err);
- if let Res::Err = ty_res {
- return Err(no_res().into());
- }
- let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
+ .and_then(|(_, res)| res.try_into())
+ .map_err(|()| no_res())?;
+
match ty_res {
Res::Def(DefKind::Enum, did) => {
if cx
/// lifetimes on `&'path` will work.
fn resolve_primitive_associated_item(
&self,
- prim_ty: hir::PrimTy,
+ prim_ty: PrimitiveType,
ns: Namespace,
module_id: DefId,
item_name: Symbol,
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let cx = self.cx;
- PrimitiveType::from_hir(prim_ty)
+ prim_ty
.impls(cx.tcx)
.into_iter()
.find_map(|&impl_| {
})
.map(|out| {
(
- Res::PrimTy(prim_ty),
- Some(format!("{}#{}.{}", prim_ty.name(), out, item_str)),
+ Res::Primitive(prim_ty),
+ Some(format!("{}#{}.{}", prim_ty.as_str(), out, item_str)),
)
})
})
.ok_or_else(|| {
debug!(
"returning primitive error for {}::{} in {} namespace",
- prim_ty.name(),
+ prim_ty.as_str(),
item_name,
ns.descr()
);
ResolutionFailure::NotResolved {
module_id,
- partial_res: Some(Res::PrimTy(prim_ty)),
+ partial_res: Some(Res::Primitive(prim_ty)),
unresolved: item_str.into(),
}
.into()
false,
) {
if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
- return Ok(res.map_id(|_| panic!("unexpected id")));
+ return Ok(res.try_into().unwrap());
}
}
- if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
- return Ok(res.map_id(|_| panic!("unexpected id")));
+ if let Some(&res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
+ return Ok(res.try_into().unwrap());
}
debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
if let Ok((_, res)) =
resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
{
// don't resolve builtins like `#[derive]`
- if let Res::Def(..) = res {
- let res = res.map_id(|_| panic!("unexpected node_id"));
+ if let Ok(res) = res.try_into() {
return Ok(res);
}
}
/// Associated items will never be resolved by this function.
fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
let result = self.cx.enter_resolver(|resolver| {
- resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+ resolver
+ .resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+ .and_then(|(_, res)| res.try_into())
});
debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
- match result.map(|(_, res)| res) {
- // resolver doesn't know about true and false so we'll have to resolve them
+ match result {
+ // resolver doesn't know about true, false, and types that aren't paths (e.g. `()`)
// manually as bool
- Ok(Res::Err) | Err(()) => is_bool_value(path_str, ns).map(|(_, res)| res),
- Ok(res) => Some(res.map_id(|_| panic!("unexpected node_id"))),
+ Err(()) => resolve_primitive(path_str, ns),
+ Ok(res) => Some(res),
}
}
return handle_variant(cx, res, extra_fragment);
}
// Not a trait item; just return what we found.
- Res::PrimTy(ty) => {
+ Res::Primitive(ty) => {
if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure(
AnchorFailure::RustdocAnchorConflict(res),
));
}
- return Ok((res, Some(ty.name_str().to_owned())));
+ return Ok((res, Some(ty.as_str().to_owned())));
}
Res::Def(DefKind::Mod, _) => {
return Ok((res, extra_fragment.clone()));
// FIXME: are these both necessary?
let ty_res = if let Some(ty_res) = resolve_primitive(&path_root, TypeNS)
- .map(|(_, res)| res)
.or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
{
ty_res
};
let res = match ty_res {
- Res::PrimTy(prim) => Some(
+ Res::Primitive(prim) => Some(
self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
),
Res::Def(
parent_node: Option<DefId>,
krate: CrateNum,
ori_link: String,
- link_range: Range<usize>,
+ link_range: Option<Range<usize>>,
) -> Option<ItemLink> {
trace!("considering link '{}'", ori_link);
(link.trim(), None)
};
- if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) {
+ if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;".contains(ch))) {
return None;
}
// Sanity check to make sure we don't have any angle brackets after stripping generics.
assert!(!path_str.contains(['<', '>'].as_slice()));
- // The link is not an intra-doc link if it still contains commas or spaces after
- // stripping generics.
- if path_str.contains([',', ' '].as_slice()) {
+ // The link is not an intra-doc link if it still contains spaces after stripping generics.
+ if path_str.contains(' ') {
return None;
}
if matches!(
disambiguator,
None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
- ) && !matches!(res, Res::PrimTy(_))
+ ) && !matches!(res, Res::Primitive(_))
{
- if let Some((path, prim)) = resolve_primitive(path_str, TypeNS) {
+ if let Some(prim) = resolve_primitive(path_str, TypeNS) {
// `prim@char`
if matches!(disambiguator, Some(Disambiguator::Primitive)) {
if fragment.is_some() {
return None;
}
res = prim;
- fragment = Some(path.as_str().to_string());
+ fragment = Some(prim.name(self.cx.tcx));
} else {
// `[char]` when a `char` module is in scope
let candidates = vec![res, prim];
};
report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, &item, dox, &link_range, callback);
};
- if let Res::PrimTy(..) = res {
- match disambiguator {
+ match res {
+ Res::Primitive(_) => match disambiguator {
Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
Some(ItemLink { link: ori_link, link_text, did: None, fragment })
}
report_mismatch(other, Disambiguator::Primitive);
None
}
- }
- } else {
- debug!("intra-doc link to {} resolved to {:?}", path_str, res);
+ },
+ Res::Def(kind, id) => {
+ debug!("intra-doc link to {} resolved to {:?}", path_str, res);
- // Disallow e.g. linking to enums with `struct@`
- if let Res::Def(kind, _) = res {
+ // Disallow e.g. linking to enums with `struct@`
debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) {
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
return None;
}
}
- }
- // item can be non-local e.g. when using #[doc(primitive = "pointer")]
- if let Some((src_id, dst_id)) = res
- .opt_def_id()
- .and_then(|def_id| def_id.as_local())
- .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
- {
- use rustc_hir::def_id::LOCAL_CRATE;
+ // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+ if let Some((src_id, dst_id)) = id
+ .as_local()
+ .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
+ {
+ use rustc_hir::def_id::LOCAL_CRATE;
- let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id);
- let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id);
+ let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id);
+ let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id);
- if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
- && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
- {
- privacy_error(cx, &item, &path_str, dox, link_range);
+ if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
+ && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
+ {
+ privacy_error(cx, &item, &path_str, dox, link_range);
+ }
}
+ let id = clean::register_res(cx, rustc_hir::def::Res::Def(kind, id));
+ Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment })
}
- let id = clean::register_res(cx, res);
- Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment })
}
}
) -> Option<(Res, Option<String>)> {
// Try to look up both the result and the corresponding side channel value
if let Some(ref cached) = self.visited_links.get(&key) {
- self.kind_side_channel.set(cached.side_channel.clone());
+ self.kind_side_channel.set(cached.side_channel);
return Some(cached.res.clone());
}
.and_then(|(res, fragment)| {
// Constructors are picked up in the type namespace.
match res {
- Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => {
+ Res::Def(DefKind::Ctor(..), _) => {
Err(ResolutionFailure::WrongNamespace(res, TypeNS))
}
- _ => match (fragment, extra_fragment.clone()) {
- (Some(fragment), Some(_)) => {
- // Shouldn't happen but who knows?
- Ok((res, Some(fragment)))
+ _ => {
+ match (fragment, extra_fragment.clone()) {
+ (Some(fragment), Some(_)) => {
+ // Shouldn't happen but who knows?
+ Ok((res, Some(fragment)))
+ }
+ (fragment, None) | (None, fragment) => Ok((res, fragment)),
}
- (fragment, None) | (None, fragment) => Ok((res, fragment)),
- },
+ }
}
}),
};
("!", DefKind::Macro(MacroKind::Bang)),
];
for &(suffix, kind) in &suffixes {
- if link.ends_with(suffix) {
- return Ok((Kind(kind), link.trim_end_matches(suffix)));
+ if let Some(link) = link.strip_suffix(suffix) {
+ // Avoid turning `!` or `()` into an empty string
+ if !link.is_empty() {
+ return Ok((Kind(kind), link));
+ }
}
}
Err(())
}
}
- /// WARNING: panics on `Res::Err`
fn from_res(res: Res) -> Self {
match res {
Res::Def(kind, _) => Disambiguator::Kind(kind),
- Res::PrimTy(_) => Disambiguator::Primitive,
- _ => Disambiguator::Namespace(res.ns().expect("can't call `from_res` on Res::err")),
+ Res::Primitive(_) => Disambiguator::Primitive,
}
}
msg: &str,
item: &Item,
dox: &str,
- link_range: &Range<usize>,
+ link_range: &Option<Range<usize>>,
decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>),
) {
let hir_id = match cx.as_local_hir_id(item.def_id) {
cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| {
let mut diag = lint.build(msg);
- let span = super::source_span_for_markdown_range(cx, dox, link_range, attrs);
- if let Some(sp) = span {
- diag.set_span(sp);
- } else {
- // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
- // ^ ~~~~
- // | link_range
- // last_new_line_offset
- let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
- let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
-
- // Print the line containing the `link_range` and manually mark it with '^'s.
- diag.note(&format!(
- "the link appears in this line:\n\n{line}\n\
- {indicator: <before$}{indicator:^<found$}",
- line = line,
- indicator = "",
- before = link_range.start - last_new_line_offset,
- found = link_range.len(),
- ));
+ let span = link_range
+ .as_ref()
+ .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs));
+
+ if let Some(link_range) = link_range {
+ if let Some(sp) = span {
+ diag.set_span(sp);
+ } else {
+ // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
+ // ^ ~~~~
+ // | link_range
+ // last_new_line_offset
+ let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
+ let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+
+ // Print the line containing the `link_range` and manually mark it with '^'s.
+ diag.note(&format!(
+ "the link appears in this line:\n\n{line}\n\
+ {indicator: <before$}{indicator:^<found$}",
+ line = line,
+ indicator = "",
+ before = link_range.start - last_new_line_offset,
+ found = link_range.len(),
+ ));
+ }
}
decorate(&mut diag, span);
path_str: &str,
disambiguator: Option<Disambiguator>,
dox: &str,
- link_range: Range<usize>,
+ link_range: Option<Range<usize>>,
kinds: SmallVec<[ResolutionFailure<'_>; 3]>,
) {
+ let tcx = collector.cx.tcx;
report_diagnostic(
collector.cx,
BROKEN_INTRA_DOC_LINKS,
dox,
&link_range,
|diag, sp| {
- let item = |res: Res| {
- format!(
- "the {} `{}`",
- res.descr(),
- collector.cx.tcx.item_name(res.def_id()).to_string()
- )
- };
+ let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),);
let assoc_item_not_allowed = |res: Res| {
- let def_id = res.def_id();
- let name = collector.cx.tcx.item_name(def_id);
+ let name = res.name(tcx);
format!(
"`{}` is {} {}, not a module or type, and cannot have associated items",
name,
if let Some(module) = last_found_module {
let note = if partial_res.is_some() {
// Part of the link resolved; e.g. `std::io::nonexistent`
- let module_name = collector.cx.tcx.item_name(module);
+ let module_name = tcx.item_name(module);
format!("no item named `{}` in module `{}`", unresolved, module_name)
} else {
// None of the link resolved; e.g. `Notimported`
// Otherwise, it must be an associated item or variant
let res = partial_res.expect("None case was handled by `last_found_module`");
- let diagnostic_name;
- let (kind, name) = match res {
- Res::Def(kind, def_id) => {
- diagnostic_name = collector.cx.tcx.item_name(def_id).as_str();
- (Some(kind), &*diagnostic_name)
- }
- Res::PrimTy(ty) => (None, ty.name_str()),
- _ => unreachable!("only ADTs and primitives are in scope at module level"),
+ let name = res.name(tcx);
+ let kind = match res {
+ Res::Def(kind, _) => Some(kind),
+ Res::Primitive(_) => None,
};
let path_description = if let Some(kind) = kind {
match kind {
item: &Item,
path_str: &str,
dox: &str,
- link_range: Range<usize>,
+ link_range: Option<Range<usize>>,
failure: AnchorFailure,
) {
let msg = match failure {
item: &Item,
path_str: &str,
dox: &str,
- link_range: Range<usize>,
+ link_range: Option<Range<usize>>,
candidates: Vec<Res>,
) {
let mut msg = format!("`{}` is ", path_str);
path_str: &str,
dox: &str,
sp: Option<rustc_span::Span>,
- link_range: &Range<usize>,
+ link_range: &Option<Range<usize>>,
) {
let suggestion = disambiguator.suggestion();
let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr());
if let Some(sp) = sp {
+ let link_range = link_range.as_ref().expect("must have a link range if we have a span");
let msg = if dox.bytes().nth(link_range.start) == Some(b'`') {
format!("`{}`", suggestion.as_help(path_str))
} else {
item: &Item,
path_str: &str,
dox: &str,
- link_range: Range<usize>,
+ link_range: Option<Range<usize>>,
) {
let sym;
let item_name = match item.name {
.parent(res.def_id())
.map(|parent| {
let parent_def = Res::Def(DefKind::Enum, parent);
- let variant = cx.tcx.expect_variant_res(res);
+ let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
(parent_def, Some(format!("variant.{}", variant.ident.name)))
})
.ok_or_else(|| ResolutionFailure::NoParentItem.into())
}
-// FIXME: At this point, this is basically a copy of the PrimitiveTypeTable
-const PRIMITIVES: &[(Symbol, Res)] = &[
- (sym::u8, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))),
- (sym::u16, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))),
- (sym::u32, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))),
- (sym::u64, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))),
- (sym::u128, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))),
- (sym::usize, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))),
- (sym::i8, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))),
- (sym::i16, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))),
- (sym::i32, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))),
- (sym::i64, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))),
- (sym::i128, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))),
- (sym::isize, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))),
- (sym::f32, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))),
- (sym::f64, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
- (sym::str, Res::PrimTy(hir::PrimTy::Str)),
- (sym::bool, Res::PrimTy(hir::PrimTy::Bool)),
- (sym::char, Res::PrimTy(hir::PrimTy::Char)),
-];
-
/// Resolve a primitive type or value.
-fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
- is_bool_value(path_str, ns).or_else(|| {
- if ns == TypeNS {
- // FIXME: this should be replaced by a lookup in PrimitiveTypeTable
- let maybe_primitive = Symbol::intern(path_str);
- PRIMITIVES.iter().find(|x| x.0 == maybe_primitive).copied()
- } else {
- None
- }
- })
-}
-
-/// Resolve a primitive value.
-fn is_bool_value(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
- if ns == TypeNS && (path_str == "true" || path_str == "false") {
- Some((sym::bool, Res::PrimTy(hir::PrimTy::Bool)))
- } else {
- None
+fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
+ if ns != TypeNS {
+ return None;
}
+ use PrimitiveType::*;
+ let prim = match path_str {
+ "isize" => Isize,
+ "i8" => I8,
+ "i16" => I16,
+ "i32" => I32,
+ "i64" => I64,
+ "i128" => I128,
+ "usize" => Usize,
+ "u8" => U8,
+ "u16" => U16,
+ "u32" => U32,
+ "u64" => U64,
+ "u128" => U128,
+ "f32" => F32,
+ "f64" => F64,
+ "char" => Char,
+ "bool" | "true" | "false" => Bool,
+ "str" => Str,
+ // See #80181 for why these don't have symbols associated.
+ "slice" => Slice,
+ "array" => Array,
+ "tuple" => Tuple,
+ "unit" => Unit,
+ "pointer" | "*" | "*const" | "*mut" => RawPointer,
+ "reference" | "&" | "&mut" => Reference,
+ "fn" => Fn,
+ "never" | "!" => Never,
+ _ => return None,
+ };
+ debug!("resolved primitives {:?}", prim);
+ Some(Res::Primitive(prim))
}
fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> {
crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
let mut synth = SyntheticImplCollector::new(cx);
- let mut krate = synth.fold_crate(krate);
+ let mut krate = cx.sess().time("collect_synthetic_impls", || synth.fold_crate(krate));
let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
let crate_items = {
let mut coll = ItemCollector::new();
- krate = coll.fold_crate(krate);
+ krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate));
coll.items
};
// Also try to inline primitive impls from other crates.
for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
if !def_id.is_local() {
- inline::build_impl(cx, None, def_id, None, &mut new_items);
+ cx.sess().time("build_primitive_trait_impl", || {
+ inline::build_impl(cx, None, def_id, None, &mut new_items);
- // FIXME(eddyb) is this `doc(hidden)` check needed?
- if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
- let self_ty = cx.tcx.type_of(def_id);
- let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
- let mut renderinfo = cx.renderinfo.borrow_mut();
+ // FIXME(eddyb) is this `doc(hidden)` check needed?
+ if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
+ let self_ty = cx.tcx.type_of(def_id);
+ let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
+ let mut renderinfo = cx.renderinfo.borrow_mut();
- new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id)));
- }
+ new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id)));
+ }
+ })
}
}
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
for it in &new_items {
- if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.kind {
+ if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
let target = items
.iter()
- .find_map(|item| match item.kind {
+ .find_map(|item| match *item.kind {
TypedefItem(ref t, true) => Some(&t.type_),
_ => None,
})
}
new_items.retain(|it| {
- if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.kind {
+ if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
cleaner.keep_item(for_)
|| trait_.as_ref().map_or(false, |t| cleaner.keep_item(t))
|| blanket_impl.is_some()
}
if let Some(ref mut it) = krate.module {
- if let ModuleItem(Module { ref mut items, .. }) = it.kind {
+ if let ModuleItem(Module { ref mut items, .. }) = *it.kind {
items.extend(synth.impls);
items.extend(new_items);
} else {
if i.is_struct() || i.is_enum() || i.is_union() {
// FIXME(eddyb) is this `doc(hidden)` check needed?
if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
- self.impls.extend(get_auto_trait_and_blanket_impls(
- self.cx,
- self.cx.tcx.type_of(i.def_id),
- i.def_id,
- ));
+ self.cx.sess().time("get_auto_trait_and_blanket_synthetic_impls", || {
+ self.impls.extend(get_auto_trait_and_blanket_impls(
+ self.cx,
+ self.cx.tcx.type_of(i.def_id),
+ i.def_id,
+ ));
+ });
}
}
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
-use rustc_middle::lint::LintSource;
+use rustc_middle::lint::LintLevelSource;
use rustc_session::lint;
crate const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
if matches!(
- item.kind,
+ *item.kind,
clean::StructFieldItem(_)
| clean::VariantItem(_)
| clean::AssocConstItem(_, _)
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local());
let (level, source) =
cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id);
- level != lint::Level::Allow || matches!(source, LintSource::Default)
+ level != lint::Level::Allow || matches!(source, LintLevelSource::Default)
}
crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
if i.attrs.lists(sym::doc).has_word(sym::hidden) {
debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
// use a dedicated hidden item for given item type if any
- match i.kind {
+ match *i.kind {
clean::StructFieldItem(..) | clean::ModuleItem(..) => {
// We need to recurse into stripped modules to
// strip things like impl methods but when doing so
let old = mem::replace(&mut self.update_retained, false);
let ret = StripItem(self.fold_item_recur(i)).strip();
self.update_retained = old;
- return ret;
+ return Some(ret);
}
_ => return None,
}
impl<'a> DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
- match i.kind {
+ match *i.kind {
clean::StrippedItem(..) => {
// We need to recurse into stripped modules to strip things
// like impl methods but when doing so we must not add any
clean::StructFieldItem(..) => {
if !i.visibility.is_public() {
- return StripItem(i).strip();
+ return Some(StripItem(i).strip());
}
}
let old = mem::replace(&mut self.update_retained, false);
let ret = StripItem(self.fold_item_recur(i)).strip();
self.update_retained = old;
- return ret;
+ return Some(ret);
}
}
clean::KeywordItem(..) => {}
}
- let fastreturn = match i.kind {
+ let fastreturn = match *i.kind {
// nothing left to do for traits (don't want to filter their
// methods out, visibility controlled by the trait)
clean::TraitItem(..) => true,
impl<'a> DocFolder for ImplStripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
- if let clean::ImplItem(ref imp) = i.kind {
+ if let clean::ImplItem(ref imp) = *i.kind {
// emptied none trait impls can be stripped
if imp.trait_.is_none() && imp.items.is_empty() {
return None;
impl DocFolder for ImportStripper {
fn fold_item(&mut self, i: Item) -> Option<Item> {
- match i.kind {
+ match *i.kind {
clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None,
_ => Some(self.fold_item_recur(i)),
}
//! The Rust AST Visitor. Extracts useful information and massages it into a form
//! usable for `clean`.
-use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
let mut module = self.visit_mod_contents(
krate.item.span,
- krate.item.attrs,
&Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public },
hir::CRATE_HIR_ID,
&krate.item.module,
fn visit_mod_contents(
&mut self,
span: Span,
- attrs: &'tcx [ast::Attribute],
vis: &'tcx hir::Visibility<'_>,
id: hir::HirId,
m: &'tcx hir::Mod<'tcx>,
name: Option<Symbol>,
) -> Module<'tcx> {
- let mut om = Module::new(name, attrs);
+ let mut om = Module::new(name);
om.where_outer = span;
om.where_inner = m.inner;
om.id = id;
hir::ItemKind::Mod(ref m) => {
om.mods.push(self.visit_mod_contents(
item.span,
- &item.attrs,
&item.vis,
item.hir_id,
m,
# stable release's version number. `date` is the date where the release we're
# bootstrapping off was released.
-date: 2020-11-18
+date: 2020-12-30
rustc: beta
# We use a nightly rustfmt to format the source because it solves some
--- /dev/null
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+// #71602: check that slice equality just generates a single bcmp
+
+// CHECK-LABEL: @is_zero_slice
+#[no_mangle]
+pub fn is_zero_slice(data: &[u8; 4]) -> bool {
+ // CHECK: start:
+ // CHECK-NEXT: %{{.+}} = getelementptr {{.+}}
+ // CHECK-NEXT: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}})
+ // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0
+ // CHECK-NEXT: ret i1 %[[EQ]]
+ *data == [0; 4]
+}
+++ /dev/null
-// compile-flags: -C codegen-units=2
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-
-fn main() {
- unsafe {
- llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
- }
-}
+++ /dev/null
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-
-fn main() {
- unsafe {
- llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
- }
-}
+++ /dev/null
-// compile-flags:-C extra-filename=-1
-#![crate_name = "crateresolve1"]
-#![crate_type = "lib"]
-
-pub fn f() -> isize { 10 }
+++ /dev/null
-// compile-flags:-C extra-filename=-2
-#![crate_name = "crateresolve1"]
-#![crate_type = "lib"]
-
-pub fn f() -> isize { 20 }
+++ /dev/null
-// compile-flags:-C extra-filename=-3
-#![crate_name = "crateresolve1"]
-#![crate_type = "lib"]
-
-pub fn f() -> isize { 30 }
+++ /dev/null
-// no-prefer-dynamic
-
-#![feature(panic_runtime)]
-#![crate_type = "rlib"]
-#![panic_runtime]
-#![no_std]
-
-extern crate needs_panic_runtime;
+++ /dev/null
-// no-prefer-dynamic
-
-#![feature(needs_panic_runtime)]
-#![crate_type = "rlib"]
-#![needs_panic_runtime]
-#![no_std]
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-#![no_std]
-#![feature(lang_items)]
-
-use core::panic::PanicInfo;
-
-#[lang = "panic_impl"]
-fn panic_impl(info: &PanicInfo) -> ! { loop {} }
-#[lang = "eh_personality"]
-fn eh_personality() {}
-#[lang = "eh_catch_typeinfo"]
-static EH_CATCH_TYPEINFO: u8 = 0;
+++ /dev/null
-// compile-flags:-C panic=unwind
-// no-prefer-dynamic
-
-#![feature(panic_runtime)]
-#![crate_type = "rlib"]
-
-#![no_std]
-#![panic_runtime]
-
-#[no_mangle]
-pub extern fn __rust_maybe_catch_panic() {}
-
-#[no_mangle]
-pub extern fn __rust_start_panic() {}
-
-#[no_mangle]
-pub extern fn rust_eh_personality() {}
+++ /dev/null
-// compile-flags:-C panic=unwind
-// no-prefer-dynamic
-
-#![feature(panic_runtime)]
-#![crate_type = "rlib"]
-
-#![no_std]
-#![panic_runtime]
-
-#[no_mangle]
-pub extern fn __rust_maybe_catch_panic() {}
-
-#[no_mangle]
-pub extern fn __rust_start_panic() {}
-
-#[no_mangle]
-pub extern fn rust_eh_personality() {}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-#![no_std]
-
-use core::panic::PanicInfo;
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
- loop {}
-}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-#![no_std]
-
-extern crate panic_runtime_unwind;
+++ /dev/null
-// no-prefer-dynamic
-
-// This aux-file will require the eh_personality function to be codegen'd, but
-// it hasn't been defined just yet. Make sure we don't explode.
-
-#![no_std]
-#![crate_type = "rlib"]
-
-struct A;
-
-impl core::ops::Drop for A {
- fn drop(&mut self) {}
-}
-
-pub fn foo() {
- let _a = A;
- panic!("wut");
-}
-
-mod std {
- pub use core::{option, fmt};
-}
+++ /dev/null
-fn main() {
- let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
- //~^ ERROR E0133
- let _: unsafe fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK
-}
+++ /dev/null
-fn main() {
- let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
- //~^ ERROR E0277
-}
+++ /dev/null
-#![feature(const_fn)]
-
-const X : usize = 2;
-
-const fn f(x: usize) -> usize {
- let mut sum = 0;
- for i in 0..x {
- //~^ ERROR mutable references
- //~| ERROR calls in constant functions
- //~| ERROR calls in constant functions
- //~| ERROR E0080
- //~| ERROR E0744
- sum += i;
- }
- sum
-}
-
-#[allow(unused_variables)]
-fn main() {
- let a : [i32; f(X)];
-}
+++ /dev/null
-// normalize-stderr-64bit "18446744073709551615" -> "SIZE"
-// normalize-stderr-32bit "4294967295" -> "SIZE"
-
-// error-pattern: are too big for the current architecture
-fn main() {
- println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
-}
+++ /dev/null
-// aux-build:crateresolve1-1.rs
-// aux-build:crateresolve1-2.rs
-// aux-build:crateresolve1-3.rs
-// error-pattern:multiple matching crates for `crateresolve1`
-
-extern crate crateresolve1;
-
-fn main() {
-}
+++ /dev/null
-// compile-flags: --extern std=
-// error-pattern: extern location for std does not exist
-
-fn main() {}
+++ /dev/null
-// ignore-msvc due to linker-flavor=ld
-// error-pattern:aFdEfSeVEEE
-// compile-flags: -C linker-flavor=ld
-
-/* Make sure invalid link_args are printed to stderr. */
-
-#![feature(link_args)]
-
-#[link_args = "aFdEfSeVEEE"]
-extern {}
-
-fn main() { }
+++ /dev/null
-// compile-flags: -C linker=llllll -C linker-flavor=ld
-// error-pattern: linker `llllll` not found
-
-fn main() {
-}
+++ /dev/null
-#![feature(associated_type_defaults)]
-
-use std::ops::Index;
-
-trait Hierarchy {
- type Value;
- type ChildKey;
- type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>;
- //~^ ERROR: the value of the associated types
-
- fn data(&self) -> Option<(Self::Value, Self::Children)>;
-}
-
-fn main() {}
+++ /dev/null
-/// The compiler previously did not properly check the bound of `From` when it was used from type
-/// of the dyn trait object (use in `copy_any` below). Since the associated type is under user
-/// control in this usage, the compiler could be tricked to believe any type implemented any trait.
-/// This would ICE, except for pure marker traits like `Copy`. It did not require providing an
-/// instance of the dyn trait type, only name said type.
-trait Setup {
- type From: Copy;
-}
-
-fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
- *from
-}
-
-pub fn copy_any<T>(t: &T) -> T {
- copy::<dyn Setup<From=T>>(t)
- //~^ ERROR the trait bound `T: Copy` is not satisfied
-}
-
-fn main() {}
+++ /dev/null
-#![feature(cfg_target_thread_local, thread_local_internals)]
-
-// On platforms *without* `#[thread_local]`, use
-// a custom non-`Sync` type to fake the same error.
-#[cfg(not(target_thread_local))]
-struct Key<T> {
- _data: std::cell::UnsafeCell<Option<T>>,
- _flag: std::cell::Cell<()>,
-}
-
-#[cfg(not(target_thread_local))]
-impl<T> Key<T> {
- const fn new() -> Self {
- Key {
- _data: std::cell::UnsafeCell::new(None),
- _flag: std::cell::Cell::new(()),
- }
- }
-}
-
-#[cfg(target_thread_local)]
-use std::thread::__FastLocalKeyInner as Key;
-
-static __KEY: Key<()> = Key::new();
-//~^ ERROR `UnsafeCell<Option<()>>` cannot be shared between threads
-//~| ERROR cannot be shared between threads safely [E0277]
-
-fn main() {}
+++ /dev/null
-#![feature(core_intrinsics)]
-
-use std::intrinsics;
-
-struct Foo {
- bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- //~^ ERROR cycle detected when simplifying constant for the type system
- x: usize,
-}
-
-fn main() {}
+++ /dev/null
-#![feature(crate_visibility_modifier)]
-
-mod rank {
- pub use self::Professor::*;
- //~^ ERROR enum is private and its variants cannot be re-exported
- pub use self::Lieutenant::{JuniorGrade, Full};
- //~^ ERROR variant `JuniorGrade` is private and cannot be re-exported
- //~| ERROR variant `Full` is private and cannot be re-exported
- pub use self::PettyOfficer::*;
- //~^ ERROR enum is private and its variants cannot be re-exported
- pub use self::Crewman::*;
- //~^ ERROR enum is private and its variants cannot be re-exported
-
- enum Professor {
- Adjunct,
- Assistant,
- Associate,
- Full
- }
-
- enum Lieutenant {
- JuniorGrade,
- Full,
- }
-
- pub(in rank) enum PettyOfficer {
- SecondClass,
- FirstClass,
- Chief,
- MasterChief
- }
-
- crate enum Crewman {
- Recruit,
- Apprentice,
- Full
- }
-
-}
-
-fn main() {}
+++ /dev/null
-fn main() {
- [(); & { loop { continue } } ]; //~ ERROR mismatched types
-
- [(); loop { break }]; //~ ERROR mismatched types
-
- [(); {while true {break}; 0}];
- //~^ WARN denote infinite loops with
-
- [(); { for _ in 0usize.. {}; 0}];
- //~^ ERROR `for` is not allowed in a `const`
- //~| ERROR calls in constants are limited to constant functions
- //~| ERROR mutable references are not allowed in constants
- //~| ERROR calls in constants are limited to constant functions
-}
+++ /dev/null
-// ignore-compare-mode-nll
-
-// revisions: a
-// should-fail
-
-// This is a "meta-test" of the compilertest framework itself. In
-// particular, it includes the right error message, but the message
-// targets the wrong revision, so we expect the execution to fail.
-// See also `meta-expected-error-correct-rev.rs`.
-
-#[cfg(a)]
-fn foo() {
- let x: u32 = 22_usize; //[b]~ ERROR mismatched types
-}
-
-fn main() { }
+++ /dev/null
-#![deny(unused_must_use)]
-#![feature(arbitrary_self_types)]
-
-use std::iter::Iterator;
-use std::future::Future;
-
-use std::task::{Context, Poll};
-use std::pin::Pin;
-use std::unimplemented;
-
-struct MyFuture;
-
-impl Future for MyFuture {
- type Output = u32;
-
- fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<u32> {
- Poll::Pending
- }
-}
-
-fn iterator() -> impl Iterator {
- std::iter::empty::<u32>()
-}
-
-fn future() -> impl Future {
- MyFuture
-}
-
-fn square_fn_once() -> impl FnOnce(u32) -> u32 {
- |x| x * x
-}
-
-fn square_fn_mut() -> impl FnMut(u32) -> u32 {
- |x| x * x
-}
-
-fn square_fn() -> impl Fn(u32) -> u32 {
- |x| x * x
-}
-
-fn main() {
- iterator(); //~ ERROR unused implementer of `Iterator` that must be used
- future(); //~ ERROR unused implementer of `Future` that must be used
- square_fn_once(); //~ ERROR unused implementer of `FnOnce` that must be used
- square_fn_mut(); //~ ERROR unused implementer of `FnMut` that must be used
- square_fn(); //~ ERROR unused implementer of `Fn` that must be used
-}
+++ /dev/null
-// error-pattern: did not contain valid UTF-8
-
-fn foo() {
- include!("not-utf8.bin")
-}
+++ /dev/null
-// error-pattern: `#[panic_handler]` function required, but not found
-
-#![feature(lang_items)]
-#![no_main]
-#![no_std]
-
-#[lang = "eh_personality"]
-fn eh() {}
+++ /dev/null
-// aux-build:some-panic-impl.rs
-
-#![feature(lang_items)]
-#![no_std]
-#![no_main]
-
-extern crate some_panic_impl;
-
-use core::panic::PanicInfo;
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
- //~^ ERROR found duplicate lang item `panic_impl`
- loop {}
-}
-
-#[lang = "eh_personality"]
-fn eh() {}
+++ /dev/null
-// aux-build:needs-panic-runtime.rs
-// aux-build:depends.rs
-// error-pattern:cannot depend on a crate that needs a panic runtime
-
-extern crate depends;
-
-fn main() {}
+++ /dev/null
-error: the crate `depends` cannot depend on a crate that needs a panic runtime, but it depends on `needs_panic_runtime`
-
-error: aborting due to previous error
-
+++ /dev/null
-// compile-fail
-#![feature(specialization)]
-//~^ WARN the feature `specialization` is incomplete
-
-pub trait Foo {
- fn foo();
-}
-
-impl Foo for i32 {}
-impl Foo for i64 {
- fn foo() {}
- //~^ERROR `foo` specializes an item from a parent `impl`
-}
-impl<T> Foo for T {
- fn foo() {}
-}
-
-fn main() {
- i32::foo();
- i64::foo();
- u8::foo();
-}
+++ /dev/null
-// error-pattern:cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
-// ignore-tidy-linelength
-// aux-build:panic-runtime-unwind.rs
-// aux-build:panic-runtime-unwind2.rs
-// aux-build:panic-runtime-lang-items.rs
-
-#![no_std]
-#![no_main]
-
-extern crate panic_runtime_unwind;
-extern crate panic_runtime_unwind2;
-extern crate panic_runtime_lang_items;
-
-fn main() {}
+++ /dev/null
-// Tests that the compiler errors if the user tries to turn off unwind tables
-// when they are required.
-//
-// compile-flags: -C panic=unwind -C force-unwind-tables=no
-// ignore-tidy-linelength
-//
-// error-pattern: panic=unwind requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
-
-pub fn main() {
-}
+++ /dev/null
-// Tests that the compiler errors if the user tries to turn off unwind tables
-// when they are required.
-//
-// only-x86_64-windows-msvc
-// compile-flags: -C force-unwind-tables=no
-// ignore-tidy-linelength
-//
-// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
-
-pub fn main() {
-}
+++ /dev/null
-// error-pattern:is not compiled with this crate's panic strategy `abort`
-// aux-build:panic-runtime-unwind.rs
-// compile-flags:-C panic=abort
-
-extern crate panic_runtime_unwind;
-
-fn main() {}
+++ /dev/null
-// error-pattern:is not compiled with this crate's panic strategy `abort`
-// aux-build:panic-runtime-unwind.rs
-// aux-build:wants-panic-runtime-unwind.rs
-// compile-flags:-C panic=abort
-
-extern crate wants_panic_runtime_unwind;
-
-fn main() {}
+++ /dev/null
-// aux-build:weak-lang-items.rs
-// error-pattern: `#[panic_handler]` function required, but not found
-// error-pattern: language item required, but not found: `eh_personality`
-// ignore-emscripten compiled with panic=abort, personality not required
-
-#![no_std]
-
-extern crate core;
-extern crate weak_lang_items;
-
-fn main() {}
// cdb-command: g
// cdb-command: dx hash_set,d
-// cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet<u64, [...]>]
-// cdb-check: [size] : 15 [Type: [...]]
+// cdb-check:hash_set,d [...] : { len=15 } [Type: [...]::HashSet<u64, [...]>]
+// cdb-check: [len] : 15 [Type: [...]]
// cdb-check: [capacity] : [...]
// cdb-check: [[...]] [...] : 0 [Type: u64]
// cdb-command: dx hash_set,d
// cdb-check: [[...]] [...] : 14 [Type: u64]
// cdb-command: dx hash_map,d
-// cdb-check:hash_map,d [...] : { size=15 } [Type: [...]::HashMap<u64, u64, [...]>]
-// cdb-check: [size] : 15 [Type: [...]]
+// cdb-check:hash_map,d [...] : { len=15 } [Type: [...]::HashMap<u64, u64, [...]>]
+// cdb-check: [len] : 15 [Type: [...]]
// cdb-check: [capacity] : [...]
// cdb-check: ["0x0"] : 0 [Type: unsigned __int64]
// cdb-command: dx hash_map,d
// NOTE: While slices have a .natvis entry that works in VS & VS Code, it fails in CDB 10.0.18362.1
// cdb-command: dx vec,d
-// cdb-check:vec,d [...] : { size=4 } [Type: [...]::Vec<u64, alloc::alloc::Global>]
-// cdb-check: [size] : 4 [Type: [...]]
+// cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec<u64, alloc::alloc::Global>]
+// cdb-check: [len] : 4 [Type: [...]]
// cdb-check: [capacity] : [...] [Type: [...]]
// cdb-check: [0] : 4 [Type: unsigned __int64]
// cdb-check: [1] : 5 [Type: unsigned __int64]
// cdb-command: dx string
// cdb-check:string : "IAMA string!" [Type: [...]::String]
// cdb-check: [<Raw View>] [Type: [...]::String]
-// cdb-check: [size] : 0xc [Type: [...]]
+// cdb-check: [len] : 0xc [Type: [...]]
// cdb-check: [capacity] : 0xc [Type: [...]]
+
+// cdb-command: dx -r2 string
// cdb-check: [0] : 73 'I' [Type: char]
// cdb-check: [1] : 65 'A' [Type: char]
// cdb-check: [2] : 77 'M' [Type: char]
// NOTE: OsString doesn't have a .natvis entry yet.
// cdb-command: dx some
-// cdb-check:some : { Some 8 } [Type: [...]::Option<i16>]
+// cdb-check:some : Some(8) [Type: [...]::Option<i16>]
// cdb-command: dx none
-// cdb-check:none : { None } [Type: [...]::Option<i64>]
+// cdb-check:none : None [Type: [...]::Option<i64>]
// cdb-command: dx some_string
-// cdb-check:some_string : { Some "IAMA optional string!" } [[...]::Option<[...]::String>]
+// cdb-check:some_string : Some("IAMA optional string!") [[...]::Option<[...]::String>]
#![allow(unused_variables)]
use std::ffi::OsString;
- _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+ _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+ // ty::Const
-+ // + ty: (u32, bool)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/checked_add.rs:5:18: 5:23
+ // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
- assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+ _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25
+ _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29
-+ // ty::Const
-+ // + ty: (u8, bool)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/indirect.rs:5:13: 5:29
+ // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
(_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
- (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
+ (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
-+ // ty::Const
-+ // + ty: (u8, u8)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/issue-67019.rs:11:10: 11:19
+ // + literal: Const { ty: (u8, u8), val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
- _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
+ _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
-+ // ty::Const
-+ // + ty: (i32, i32)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14
+ // + literal: Const { ty: (i32, i32), val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ // ty::Const
-+ // + ty: (i32, bool)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
- _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+ _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+ // ty::Const
-+ // + ty: (i32, bool)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
+ // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
- _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+ _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+ // ty::Const
-+ // + ty: (u32, bool)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/return_place.rs:6:5: 6:10
+ // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
- _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
+ _3 = const (1_u32, 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
-+ // ty::Const
-+ // + ty: (u32, u32)
-+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
+ // mir::Constant
+ // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
+ // + literal: Const { ty: (u32, u32), val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
fn forget(_1: T) -> () {
debug t => _1; // in scope 0 at $DIR/lower_intrinsics.rs:18:18: 18:19
let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:18:24: 18:24
- let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:19:14: 19:41
- let mut _3: T; // in scope 0 at $DIR/lower_intrinsics.rs:19:39: 19:40
- scope 1 {
- }
+ let mut _2: T; // in scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31
bb0: {
- StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:43
- StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:19:39: 19:40
- _3 = move _1; // scope 1 at $DIR/lower_intrinsics.rs:19:39: 19:40
-- _2 = std::intrinsics::forget::<T>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:19:14: 19:41
+ StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31
+ _2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:19:30: 19:31
+- _0 = std::intrinsics::forget::<T>(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32
- // mir::Constant
-- // + span: $DIR/lower_intrinsics.rs:19:14: 19:38
-- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(Scalar(<ZST>)) }
-+ _2 = const (); // scope 1 at $DIR/lower_intrinsics.rs:19:14: 19:41
-+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:19:14: 19:41
+- // + span: $DIR/lower_intrinsics.rs:19:5: 19:29
+- // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(Scalar(<ZST>)) }
++ _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32
++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:32
}
bb1: {
- StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:19:40: 19:41
- StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:19:43: 19:44
- _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:18:24: 20:2
+ StorageDead(_2); // scope 0 at $DIR/lower_intrinsics.rs:19:31: 19:32
goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:20:1: 20:2
}
// EMIT_MIR lower_intrinsics.forget.LowerIntrinsics.diff
pub fn forget<T>(t: T) {
- unsafe { core::intrinsics::forget(t) };
+ core::intrinsics::forget(t)
}
// EMIT_MIR lower_intrinsics.unreachable.LowerIntrinsics.diff
// mir::Constant
// + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12
// + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar(<ZST>)) }
- // ty::Const
- // + ty: ((), ())
- // + val: Value(Scalar(<ZST>))
// mir::Constant
// + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
// + literal: Const { ty: ((), ()), val: Value(Scalar(<ZST>)) }
# Run it in order to generate some profiling data,
# with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
# output the coverage stats for this run.
- LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \
+ LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
$(call RUN,$@) || \
( \
status=$$?; \
) \
)
+ # Run it through rustdoc as well to cover doctests
+ LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
+ $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \
+ $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \
+ -L "$(TMPDIR)" -Zinstrument-coverage \
+ -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@
+
# Postprocess the profiling data so it can be used by the llvm-cov tool
"$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
- "$(TMPDIR)"/$@.profraw \
+ "$(TMPDIR)"/$@-*.profraw \
-o "$(TMPDIR)"/$@.profdata
# Generate a coverage report using `llvm-cov show`.
--show-line-counts-or-regions \
--instr-profile="$(TMPDIR)"/$@.profdata \
$(call BIN,"$(TMPDIR)"/$@) \
- > "$(TMPDIR)"/actual_show_coverage.$@.txt \
- 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt || \
+ $$( \
+ for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \
+ do \
+ [[ -x $$file ]] && printf "%s %s " -object $$file; \
+ done \
+ ) \
+ 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \
+ | "$(PYTHON)" $(BASEDIR)/normalize_paths.py \
+ > "$(TMPDIR)"/actual_show_coverage.$@.txt || \
( status=$$? ; \
>&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \
exit $$status \
--- /dev/null
+../coverage/doctest.rs:
+ 1| |//! This test ensures that code from doctests is properly re-mapped.
+ 2| |//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
+ 3| |//!
+ 4| |//! Just some random code:
+ 5| 1|//! ```
+ 6| 1|//! if true {
+ 7| |//! // this is executed!
+ 8| 1|//! assert_eq!(1, 1);
+ 9| |//! } else {
+ 10| |//! // this is not!
+ 11| |//! assert_eq!(1, 2);
+ 12| |//! }
+ 13| 1|//! ```
+ 14| |//!
+ 15| |//! doctest testing external code:
+ 16| |//! ```
+ 17| 1|//! extern crate doctest_crate;
+ 18| 1|//! doctest_crate::fn_run_in_doctests(1);
+ 19| 1|//! ```
+ 20| |//!
+ 21| |//! doctest returning a result:
+ 22| 1|//! ```
+ 23| 1|//! #[derive(Debug)]
+ 24| 1|//! struct SomeError;
+ 25| 1|//! let mut res = Err(SomeError);
+ 26| 1|//! if res.is_ok() {
+ 27| 0|//! res?;
+ 28| 1|//! } else {
+ 29| 1|//! res = Ok(0);
+ 30| 1|//! }
+ 31| |//! // need to be explicit because rustdoc cant infer the return type
+ 32| 1|//! Ok::<(), SomeError>(())
+ 33| 1|//! ```
+ 34| |//!
+ 35| |//! doctest with custom main:
+ 36| |//! ```
+ 37| |//! #[derive(Debug)]
+ 38| |//! struct SomeError;
+ 39| |//!
+ 40| |//! extern crate doctest_crate;
+ 41| |//!
+ 42| 1|//! fn doctest_main() -> Result<(), SomeError> {
+ 43| 1|//! doctest_crate::fn_run_in_doctests(2);
+ 44| 1|//! Ok(())
+ 45| 1|//! }
+ 46| |//!
+ 47| |//! // this `main` is not shown as covered, as it clashes with all the other
+ 48| |//! // `main` functions that were automatically generated for doctests
+ 49| |//! fn main() -> Result<(), SomeError> {
+ 50| |//! doctest_main()
+ 51| |//! }
+ 52| |//! ```
+ 53| |
+ 54| |/// doctest attached to fn testing external code:
+ 55| |/// ```
+ 56| 1|/// extern crate doctest_crate;
+ 57| 1|/// doctest_crate::fn_run_in_doctests(3);
+ 58| 1|/// ```
+ 59| |///
+ 60| 1|fn main() {
+ 61| 1| if true {
+ 62| 1| assert_eq!(1, 1);
+ 63| | } else {
+ 64| | assert_eq!(1, 2);
+ 65| | }
+ 66| 1|}
+
+../coverage/lib/doctest_crate.rs:
+ 1| |/// A function run only from within doctests
+ 2| 3|pub fn fn_run_in_doctests(conditional: usize) {
+ 3| 3| match conditional {
+ 4| 1| 1 => assert_eq!(1, 1), // this is run,
+ 5| 1| 2 => assert_eq!(1, 1), // this,
+ 6| 1| 3 => assert_eq!(1, 1), // and this too
+ 7| 0| _ => assert_eq!(1, 2), // however this is not
+ 8| | }
+ 9| 3|}
+
18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
19| 2|}
------------------
- | used_crate::used_only_from_bin_crate_generic_function::<&str>:
+ | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
| 19| 1|}
------------------
- | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+ | used_crate::used_only_from_bin_crate_generic_function::<&str>:
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
| 19| 1|}
--- /dev/null
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import sys
+
+# Normalize file paths in output
+for line in sys.stdin:
+ if line.startswith("..") and line.rstrip().endswith(".rs:"):
+ print(line.replace("\\", "/"), end='')
+ else:
+ print(line, end='')
--- /dev/null
+<!DOCTYPE html>
+<!--
+
+Preview this file as rendered HTML from the github source at:
+https://htmlpreview.github.io/?https://github.com/rust-lang/rust/blob/master/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html
+
+For revisions in Pull Requests (PR):
+ * Replace "rust-lang" with the github PR author
+ * Replace "master" with the PR branch name
+
+-->
+<html>
+<head>
+<title>doctest.main - Coverage Spans</title>
+<style>
+ .line {
+ counter-increment: line;
+ }
+ .line:before {
+ content: counter(line) ": ";
+ font-family: Menlo, Monaco, monospace;
+ font-style: italic;
+ width: 3.8em;
+ display: inline-block;
+ text-align: right;
+ filter: opacity(50%);
+ -webkit-user-select: none;
+ }
+ .code {
+ color: #dddddd;
+ background-color: #222222;
+ font-family: Menlo, Monaco, monospace;
+ line-height: 1.4em;
+ border-bottom: 2px solid #222222;
+ white-space: pre;
+ display: inline-block;
+ }
+ .odd {
+ background-color: #55bbff;
+ color: #223311;
+ }
+ .even {
+ background-color: #ee7756;
+ color: #551133;
+ }
+ .code {
+ --index: calc(var(--layer) - 1);
+ padding-top: calc(var(--index) * 0.15em);
+ filter:
+ hue-rotate(calc(var(--index) * 25deg))
+ saturate(calc(100% - (var(--index) * 2%)))
+ brightness(calc(100% - (var(--index) * 1.5%)));
+ }
+ .annotation {
+ color: #4444ff;
+ font-family: monospace;
+ font-style: italic;
+ display: none;
+ -webkit-user-select: none;
+ }
+ body:active .annotation {
+ /* requires holding mouse down anywhere on the page */
+ display: inline-block;
+ }
+ span:hover .annotation {
+ /* requires hover over a span ONLY on its first line */
+ display: inline-block;
+ }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 59"><span class="line"><span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>fn main() <span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">{</span></span>
+<span class="line"><span class="code" style="--layer: 0"> if </span><span><span class="code even" style="--layer: 1" title="61:8-61:12: @0[1]: _1 = const true
+61:8-61:12: @0[2]: FakeRead(ForMatchedPlace, _1)"><span class="annotation">@0⦊</span>true<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="62:9-62:26: @5[0]: _2 = const ()"><span class="annotation">@5⦊</span></span></span><span class="code even" style="--layer: 2" title="62:9-62:26: @6[5]: _75 = const main::promoted[3]
+62:9-62:26: @6[6]: _18 = &(*_75)
+62:9-62:26: @6[7]: _17 = &(*_18)
+62:9-62:26: @6[8]: _16 = move _17 as &[&str] (Pointer(Unsize))
+62:9-62:26: @6[17]: _26 = &(*_8)
+62:9-62:26: @6[18]: _25 = &_26
+62:9-62:26: @6[21]: _28 = &(*_9)
+62:9-62:26: @6[22]: _27 = &_28
+62:9-62:26: @6[23]: _24 = (move _25, move _27)
+62:9-62:26: @6[26]: FakeRead(ForMatchedPlace, _24)
+62:9-62:26: @6[28]: _29 = (_24.0: &&i32)
+62:9-62:26: @6[30]: _30 = (_24.1: &&i32)
+62:9-62:26: @6[33]: _32 = &(*_29)
+62:9-62:26: @6[35]: _33 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+62:9-62:26: @6.Call: _31 = ArgumentV1::new::<&i32>(move _32, move _33) -> [return: bb7, unwind: bb17]
+62:9-62:26: @7[4]: _35 = &(*_30)
+62:9-62:26: @7[6]: _36 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+62:9-62:26: @7.Call: _34 = ArgumentV1::new::<&i32>(move _35, move _36) -> [return: bb8, unwind: bb17]
+62:9-62:26: @8[2]: _23 = [move _31, move _34]
+62:9-62:26: @8[7]: _22 = &_23
+62:9-62:26: @8[8]: _21 = &(*_22)
+62:9-62:26: @8[9]: _20 = move _21 as &[std::fmt::ArgumentV1] (Pointer(Unsize))
+62:9-62:26: @8.Call: _15 = Arguments::new_v1(move _16, move _20) -> [return: bb9, unwind: bb17]
+62:9-62:26: @9.Call: core::panicking::panic_fmt(move _15) -> bb17"><span class="annotation">@4,6,7,8,9⦊</span>assert_eq!(1, 1);<span class="annotation">⦉@4,6,7,8,9</span></span><span><span class="code odd" style="--layer: 1" title="62:9-62:26: @5[0]: _2 = const ()"><span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"> } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="64:9-64:26: @11[0]: _37 = const ()"><span class="annotation">@11⦊</span></span></span><span class="code even" style="--layer: 2" title="64:9-64:26: @12[5]: _72 = const main::promoted[0]
+64:9-64:26: @12[6]: _53 = &(*_72)
+64:9-64:26: @12[7]: _52 = &(*_53)
+64:9-64:26: @12[8]: _51 = move _52 as &[&str] (Pointer(Unsize))
+64:9-64:26: @12[17]: _61 = &(*_43)
+64:9-64:26: @12[18]: _60 = &_61
+64:9-64:26: @12[21]: _63 = &(*_44)
+64:9-64:26: @12[22]: _62 = &_63
+64:9-64:26: @12[23]: _59 = (move _60, move _62)
+64:9-64:26: @12[26]: FakeRead(ForMatchedPlace, _59)
+64:9-64:26: @12[28]: _64 = (_59.0: &&i32)
+64:9-64:26: @12[30]: _65 = (_59.1: &&i32)
+64:9-64:26: @12[33]: _67 = &(*_64)
+64:9-64:26: @12[35]: _68 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+64:9-64:26: @12.Call: _66 = ArgumentV1::new::<&i32>(move _67, move _68) -> [return: bb13, unwind: bb17]
+64:9-64:26: @13[4]: _70 = &(*_65)
+64:9-64:26: @13[6]: _71 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+64:9-64:26: @13.Call: _69 = ArgumentV1::new::<&i32>(move _70, move _71) -> [return: bb14, unwind: bb17]
+64:9-64:26: @14[2]: _58 = [move _66, move _69]
+64:9-64:26: @14[7]: _57 = &_58
+64:9-64:26: @14[8]: _56 = &(*_57)
+64:9-64:26: @14[9]: _55 = move _56 as &[std::fmt::ArgumentV1] (Pointer(Unsize))
+64:9-64:26: @14.Call: _50 = Arguments::new_v1(move _51, move _55) -> [return: bb15, unwind: bb17]
+64:9-64:26: @15.Call: core::panicking::panic_fmt(move _50) -> bb17"><span class="annotation">@10,12,13,14,15⦊</span>assert_eq!(1, 2);<span class="annotation">⦉@10,12,13,14,15</span></span><span><span class="code even" style="--layer: 1" title="64:9-64:26: @11[0]: _37 = const ()"><span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"> }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="66:2-66:2: @16.Return: return"><span class="annotation">@16⦊</span>‸<span class="annotation">⦉@16</span></span></span></span></div>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<!--
+
+Preview this file as rendered HTML from the github source at:
+https://htmlpreview.github.io/?https://github.com/rust-lang/rust/blob/master/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html
+
+For revisions in Pull Requests (PR):
+ * Replace "rust-lang" with the github PR author
+ * Replace "master" with the PR branch name
+
+-->
+<html>
+<head>
+<title>doctest_crate.fn_run_in_doctests - Coverage Spans</title>
+<style>
+ .line {
+ counter-increment: line;
+ }
+ .line:before {
+ content: counter(line) ": ";
+ font-family: Menlo, Monaco, monospace;
+ font-style: italic;
+ width: 3.8em;
+ display: inline-block;
+ text-align: right;
+ filter: opacity(50%);
+ -webkit-user-select: none;
+ }
+ .code {
+ color: #dddddd;
+ background-color: #222222;
+ font-family: Menlo, Monaco, monospace;
+ line-height: 1.4em;
+ border-bottom: 2px solid #222222;
+ white-space: pre;
+ display: inline-block;
+ }
+ .odd {
+ background-color: #55bbff;
+ color: #223311;
+ }
+ .even {
+ background-color: #ee7756;
+ color: #551133;
+ }
+ .code {
+ --index: calc(var(--layer) - 1);
+ padding-top: calc(var(--index) * 0.15em);
+ filter:
+ hue-rotate(calc(var(--index) * 25deg))
+ saturate(calc(100% - (var(--index) * 2%)))
+ brightness(calc(100% - (var(--index) * 1.5%)));
+ }
+ .annotation {
+ color: #4444ff;
+ font-family: monospace;
+ font-style: italic;
+ display: none;
+ -webkit-user-select: none;
+ }
+ body:active .annotation {
+ /* requires holding mouse down anywhere on the page */
+ display: inline-block;
+ }
+ span:hover .annotation {
+ /* requires hover over a span ONLY on its first line */
+ display: inline-block;
+ }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 1"><span class="line"><span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>pub fn fn_run_in_doctests(conditional: usize) <span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">{</span></span>
+<span class="line"><span class="code" style="--layer: 0"> match </span><span><span class="code even" style="--layer: 1" title="3:11-3:22: @0[0]: FakeRead(ForMatchedPlace, _1)"><span class="annotation">@0⦊</span>conditional<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0"> 1 => </span><span><span class="code odd" style="--layer: 1" title="4:14-4:30: @7[0]: _0 = const ()"><span class="annotation">@7⦊</span></span></span><span class="code even" style="--layer: 2" title="4:14-4:30: @8[5]: _138 = const fn_run_in_doctests::promoted[0]
+4:14-4:30: @8[6]: _17 = &(*_138)
+4:14-4:30: @8[7]: _16 = &(*_17)
+4:14-4:30: @8[8]: _15 = move _16 as &[&str] (Pointer(Unsize))
+4:14-4:30: @8[17]: _25 = &(*_7)
+4:14-4:30: @8[18]: _24 = &_25
+4:14-4:30: @8[21]: _27 = &(*_8)
+4:14-4:30: @8[22]: _26 = &_27
+4:14-4:30: @8[23]: _23 = (move _24, move _26)
+4:14-4:30: @8[26]: FakeRead(ForMatchedPlace, _23)
+4:14-4:30: @8[28]: _28 = (_23.0: &&i32)
+4:14-4:30: @8[30]: _29 = (_23.1: &&i32)
+4:14-4:30: @8[33]: _31 = &(*_28)
+4:14-4:30: @8[35]: _32 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+4:14-4:30: @8.Call: _30 = ArgumentV1::new::<&i32>(move _31, move _32) -> [return: bb9, unwind: bb33]
+4:14-4:30: @9[4]: _34 = &(*_29)
+4:14-4:30: @9[6]: _35 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+4:14-4:30: @9.Call: _33 = ArgumentV1::new::<&i32>(move _34, move _35) -> [return: bb10, unwind: bb33]
+4:14-4:30: @10[2]: _22 = [move _30, move _33]
+4:14-4:30: @10[7]: _21 = &_22
+4:14-4:30: @10[8]: _20 = &(*_21)
+4:14-4:30: @10[9]: _19 = move _20 as &[std::fmt::ArgumentV1] (Pointer(Unsize))
+4:14-4:30: @10.Call: _14 = Arguments::new_v1(move _15, move _19) -> [return: bb11, unwind: bb33]
+4:14-4:30: @11.Call: core::panicking::panic_fmt(move _14) -> bb33"><span class="annotation">@6,8,9,10,11⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@6,8,9,10,11</span></span><span><span class="code odd" style="--layer: 1" title="4:14-4:30: @7[0]: _0 = const ()"><span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0">, // this is run,</span></span>
+<span class="line"><span class="code" style="--layer: 0"> 2 => </span><span><span class="code even" style="--layer: 1" title="5:14-5:30: @14[0]: _0 = const ()"><span class="annotation">@14⦊</span></span></span><span class="code even" style="--layer: 2" title="5:14-5:30: @15[5]: _141 = const fn_run_in_doctests::promoted[3]
+5:14-5:30: @15[6]: _51 = &(*_141)
+5:14-5:30: @15[7]: _50 = &(*_51)
+5:14-5:30: @15[8]: _49 = move _50 as &[&str] (Pointer(Unsize))
+5:14-5:30: @15[17]: _59 = &(*_41)
+5:14-5:30: @15[18]: _58 = &_59
+5:14-5:30: @15[21]: _61 = &(*_42)
+5:14-5:30: @15[22]: _60 = &_61
+5:14-5:30: @15[23]: _57 = (move _58, move _60)
+5:14-5:30: @15[26]: FakeRead(ForMatchedPlace, _57)
+5:14-5:30: @15[28]: _62 = (_57.0: &&i32)
+5:14-5:30: @15[30]: _63 = (_57.1: &&i32)
+5:14-5:30: @15[33]: _65 = &(*_62)
+5:14-5:30: @15[35]: _66 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+5:14-5:30: @15.Call: _64 = ArgumentV1::new::<&i32>(move _65, move _66) -> [return: bb16, unwind: bb33]
+5:14-5:30: @16[4]: _68 = &(*_63)
+5:14-5:30: @16[6]: _69 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+5:14-5:30: @16.Call: _67 = ArgumentV1::new::<&i32>(move _68, move _69) -> [return: bb17, unwind: bb33]
+5:14-5:30: @17[2]: _56 = [move _64, move _67]
+5:14-5:30: @17[7]: _55 = &_56
+5:14-5:30: @17[8]: _54 = &(*_55)
+5:14-5:30: @17[9]: _53 = move _54 as &[std::fmt::ArgumentV1] (Pointer(Unsize))
+5:14-5:30: @17.Call: _48 = Arguments::new_v1(move _49, move _53) -> [return: bb18, unwind: bb33]
+5:14-5:30: @18.Call: core::panicking::panic_fmt(move _48) -> bb33"><span class="annotation">@13,15,16,17,18⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@13,15,16,17,18</span></span><span><span class="code even" style="--layer: 1" title="5:14-5:30: @14[0]: _0 = const ()"><span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0">, // this,</span></span>
+<span class="line"><span class="code" style="--layer: 0"> 3 => </span><span><span class="code odd" style="--layer: 1" title="6:14-6:30: @21[0]: _0 = const ()"><span class="annotation">@21⦊</span></span></span><span class="code even" style="--layer: 2" title="6:14-6:30: @22[5]: _144 = const fn_run_in_doctests::promoted[6]
+6:14-6:30: @22[6]: _85 = &(*_144)
+6:14-6:30: @22[7]: _84 = &(*_85)
+6:14-6:30: @22[8]: _83 = move _84 as &[&str] (Pointer(Unsize))
+6:14-6:30: @22[17]: _93 = &(*_75)
+6:14-6:30: @22[18]: _92 = &_93
+6:14-6:30: @22[21]: _95 = &(*_76)
+6:14-6:30: @22[22]: _94 = &_95
+6:14-6:30: @22[23]: _91 = (move _92, move _94)
+6:14-6:30: @22[26]: FakeRead(ForMatchedPlace, _91)
+6:14-6:30: @22[28]: _96 = (_91.0: &&i32)
+6:14-6:30: @22[30]: _97 = (_91.1: &&i32)
+6:14-6:30: @22[33]: _99 = &(*_96)
+6:14-6:30: @22[35]: _100 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+6:14-6:30: @22.Call: _98 = ArgumentV1::new::<&i32>(move _99, move _100) -> [return: bb23, unwind: bb33]
+6:14-6:30: @23[4]: _102 = &(*_97)
+6:14-6:30: @23[6]: _103 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+6:14-6:30: @23.Call: _101 = ArgumentV1::new::<&i32>(move _102, move _103) -> [return: bb24, unwind: bb33]
+6:14-6:30: @24[2]: _90 = [move _98, move _101]
+6:14-6:30: @24[7]: _89 = &_90
+6:14-6:30: @24[8]: _88 = &(*_89)
+6:14-6:30: @24[9]: _87 = move _88 as &[std::fmt::ArgumentV1] (Pointer(Unsize))
+6:14-6:30: @24.Call: _82 = Arguments::new_v1(move _83, move _87) -> [return: bb25, unwind: bb33]
+6:14-6:30: @25.Call: core::panicking::panic_fmt(move _82) -> bb33"><span class="annotation">@20,22,23,24,25⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@20,22,23,24,25</span></span><span><span class="code odd" style="--layer: 1" title="6:14-6:30: @21[0]: _0 = const ()"><span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0">, // and this too</span></span>
+<span class="line"><span class="code" style="--layer: 0"> _ => </span><span><span class="code even" style="--layer: 1" title="7:14-7:30: @27[0]: _0 = const ()"><span class="annotation">@27⦊</span></span></span><span class="code even" style="--layer: 2" title="7:14-7:30: @28[5]: _147 = const fn_run_in_doctests::promoted[9]
+7:14-7:30: @28[6]: _119 = &(*_147)
+7:14-7:30: @28[7]: _118 = &(*_119)
+7:14-7:30: @28[8]: _117 = move _118 as &[&str] (Pointer(Unsize))
+7:14-7:30: @28[17]: _127 = &(*_109)
+7:14-7:30: @28[18]: _126 = &_127
+7:14-7:30: @28[21]: _129 = &(*_110)
+7:14-7:30: @28[22]: _128 = &_129
+7:14-7:30: @28[23]: _125 = (move _126, move _128)
+7:14-7:30: @28[26]: FakeRead(ForMatchedPlace, _125)
+7:14-7:30: @28[28]: _130 = (_125.0: &&i32)
+7:14-7:30: @28[30]: _131 = (_125.1: &&i32)
+7:14-7:30: @28[33]: _133 = &(*_130)
+7:14-7:30: @28[35]: _134 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+7:14-7:30: @28.Call: _132 = ArgumentV1::new::<&i32>(move _133, move _134) -> [return: bb29, unwind: bb33]
+7:14-7:30: @29[4]: _136 = &(*_131)
+7:14-7:30: @29[6]: _137 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer))
+7:14-7:30: @29.Call: _135 = ArgumentV1::new::<&i32>(move _136, move _137) -> [return: bb30, unwind: bb33]
+7:14-7:30: @30[2]: _124 = [move _132, move _135]
+7:14-7:30: @30[7]: _123 = &_124
+7:14-7:30: @30[8]: _122 = &(*_123)
+7:14-7:30: @30[9]: _121 = move _122 as &[std::fmt::ArgumentV1] (Pointer(Unsize))
+7:14-7:30: @30.Call: _116 = Arguments::new_v1(move _117, move _121) -> [return: bb31, unwind: bb33]
+7:14-7:30: @31.Call: core::panicking::panic_fmt(move _116) -> bb33"><span class="annotation">@26,28,29,30,31⦊</span>assert_eq!(1, 2)<span class="annotation">⦉@26,28,29,30,31</span></span><span><span class="code even" style="--layer: 1" title="7:14-7:30: @27[0]: _0 = const ()"><span class="annotation">⦉@27</span></span></span><span class="code" style="--layer: 0">, // however this is not</span></span>
+<span class="line"><span class="code" style="--layer: 0"> }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="9:2-9:2: @32.Return: return"><span class="annotation">@32⦊</span>‸<span class="annotation">⦉@32</span></span></span></span></div>
+</body>
+</html>
-# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-*
+# Directory "coverage" supports the tests at prefix ../coverage-*
-# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests.
+# Use ./x.py [options] test src/test/run-make-fulldeps/coverage to run all related tests.
-# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this
+# Common Makefile include for Rust `run-make-fulldeps/coverage-* tests. Include this
# file with the line:
#
-# -include ../instrument-coverage/coverage_tools.mk
+# -include ../coverage/coverage_tools.mk
-include ../tools.mk
--- /dev/null
+//! This test ensures that code from doctests is properly re-mapped.
+//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
+//!
+//! Just some random code:
+//! ```
+//! if true {
+//! // this is executed!
+//! assert_eq!(1, 1);
+//! } else {
+//! // this is not!
+//! assert_eq!(1, 2);
+//! }
+//! ```
+//!
+//! doctest testing external code:
+//! ```
+//! extern crate doctest_crate;
+//! doctest_crate::fn_run_in_doctests(1);
+//! ```
+//!
+//! doctest returning a result:
+//! ```
+//! #[derive(Debug)]
+//! struct SomeError;
+//! let mut res = Err(SomeError);
+//! if res.is_ok() {
+//! res?;
+//! } else {
+//! res = Ok(0);
+//! }
+//! // need to be explicit because rustdoc cant infer the return type
+//! Ok::<(), SomeError>(())
+//! ```
+//!
+//! doctest with custom main:
+//! ```
+//! #[derive(Debug)]
+//! struct SomeError;
+//!
+//! extern crate doctest_crate;
+//!
+//! fn doctest_main() -> Result<(), SomeError> {
+//! doctest_crate::fn_run_in_doctests(2);
+//! Ok(())
+//! }
+//!
+//! // this `main` is not shown as covered, as it clashes with all the other
+//! // `main` functions that were automatically generated for doctests
+//! fn main() -> Result<(), SomeError> {
+//! doctest_main()
+//! }
+//! ```
+
+/// doctest attached to fn testing external code:
+/// ```
+/// extern crate doctest_crate;
+/// doctest_crate::fn_run_in_doctests(3);
+/// ```
+///
+fn main() {
+ if true {
+ assert_eq!(1, 1);
+ } else {
+ assert_eq!(1, 2);
+ }
+}
--- /dev/null
+/// A function run only from within doctests
+pub fn fn_run_in_doctests(conditional: usize) {
+ match conditional {
+ 1 => assert_eq!(1, 1), // this is run,
+ 2 => assert_eq!(1, 1), // this,
+ 3 => assert_eq!(1, 1), // and this too
+ _ => assert_eq!(1, 2), // however this is not
+ }
+}
-include ../tools.mk
-# Modelled after compile-fail/changing-crates test, but this one puts
+# Modelled after ui/changing-crates.rs test, but this one puts
# more than one (mismatching) candidate crate into the search path,
-# which did not appear directly expressible in compile-fail/aux-build
-# infrastructure.
+# which did not appear directly expressible in UI testing infrastructure.
#
# Note that we move the built libraries into target direcrtories rather than
# use the `--out-dir` option because the `../tools.mk` file already bakes a
'crate `crateA`:' \
'crate `crateB`:' \
< $(LOG)
- # the 'crate `crateA`' will match two entries.
\ No newline at end of file
+ # the 'crate `crateA`' will match two entries.
--- /dev/null
+-include ../tools.mk
+
+all:
+ echo 'fn main(){}' | $(RUSTC) -Z no-link -
+ $(RUSTC) -Z link-only $(TMPDIR)/rust_out.rlink
+ $(call RUN,rust_out)
// causing a type mismatch.
// The test is nearly the same as the one in
-// compile-fail/type-mismatch-same-crate-name.rs
+// ui/type/type-mismatch-same-crate-name.rs
// but deals with the case where one of the crates
// is only introduced as an indirect dependency.
// and the type is accessed via a re-export.
// check-pass
// edition:2018
-#![feature(min_const_generics)]
trait ValidTrait {}
/// This has docs
--- /dev/null
+#![deny(broken_intra_doc_links)]
+// These are links that could reasonably expected to work, but don't.
+
+// `[]` isn't supported because it had too many false positives.
+//! [X]([T]::not_here)
+//! [Y](&[]::not_here)
+//! [X]([]::not_here)
+//! [Y]([T;N]::not_here)
+
+// These don't work because markdown syntax doesn't allow it.
+//! [[T]::rotate_left] //~ ERROR unresolved link to `T`
+//! [&[]::not_here]
+//![Z]([T; N]::map) //~ ERROR unresolved link to `Z`
+//! [`[T; N]::map`]
+//! [[]::map]
+//! [Z][] //~ ERROR unresolved link to `Z`
+//!
+//! [Z]: [T; N]::map //~ ERROR unresolved link to `Z`
+
+// `()` isn't supported because it had too many false positives.
+//! [()::not_here]
+//! [X]((,)::not_here)
+//! [(,)::not_here]
+
+// FIXME: Associated items on some primitives aren't working, because the impls
+// are part of the compiler instead of being part of the source code.
+//! [unit::eq] //~ ERROR unresolved
+//! [tuple::eq] //~ ERROR unresolved
+//! [fn::eq] //~ ERROR unresolved
+//! [never::eq] //~ ERROR unresolved
+
+// FIXME(#78800): This breaks because it's a blanket impl
+// (I think? Might break for other reasons too.)
+//! [reference::deref] //~ ERROR unresolved
--- /dev/null
+error: unresolved link to `T`
+ --> $DIR/non-path-primitives.rs:11:7
+ |
+LL | //! [[T]::rotate_left]
+ | ^ no item named `T` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/non-path-primitives.rs:1:9
+ |
+LL | #![deny(broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+ --> $DIR/non-path-primitives.rs:13:5
+ |
+LL | //![Z]([T; N]::map)
+ | ^ no item named `Z` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+ --> $DIR/non-path-primitives.rs:16:6
+ |
+LL | //! [Z][]
+ | ^ no item named `Z` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Z`
+ --> $DIR/non-path-primitives.rs:18:6
+ |
+LL | //! [Z]: [T; N]::map
+ | ^ no item named `Z` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `unit::eq`
+ --> $DIR/non-path-primitives.rs:27:6
+ |
+LL | //! [unit::eq]
+ | ^^^^^^^^ the builtin type `unit` has no associated item named `eq`
+
+error: unresolved link to `tuple::eq`
+ --> $DIR/non-path-primitives.rs:28:6
+ |
+LL | //! [tuple::eq]
+ | ^^^^^^^^^ the builtin type `tuple` has no associated item named `eq`
+
+error: unresolved link to `fn::eq`
+ --> $DIR/non-path-primitives.rs:29:6
+ |
+LL | //! [fn::eq]
+ | ^^^^^^ the builtin type `fn` has no associated item named `eq`
+
+error: unresolved link to `never::eq`
+ --> $DIR/non-path-primitives.rs:30:6
+ |
+LL | //! [never::eq]
+ | ^^^^^^^^^ the builtin type `never` has no associated item named `eq`
+
+error: unresolved link to `reference::deref`
+ --> $DIR/non-path-primitives.rs:34:6
+ |
+LL | //! [reference::deref]
+ | ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
+
+error: aborting due to 9 previous errors
+
+++ /dev/null
-// ignore-test
-// check-pass
-
-/// docs [label][with#anchor#error]
-//~^ WARNING has an issue with the link anchor
-pub struct S;
+++ /dev/null
-warning: `[with#anchor#error]` has an issue with the link anchor.
- --> $DIR/reference-link-has-one-warning.rs:3:18
- |
-LL | /// docs [label][with#anchor#error]
- | ^^^^^^^^^^^^^^^^^ only one `#` is allowed in a link
- |
- = note: `#[warn(broken_intra_doc_links)]` on by default
-
-warning: 1 warning emitted
-
--- /dev/null
+// Test that errors point to the reference, not to the title text.
+#![deny(broken_intra_doc_links)]
+//! Links to [a] [link][a]
+//!
+//! [a]: std::process::Comman
+//~^ ERROR unresolved
+//~| ERROR unresolved
--- /dev/null
+error: unresolved link to `std::process::Comman`
+ --> $DIR/reference-links.rs:5:10
+ |
+LL | //! [a]: std::process::Comman
+ | ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process`
+ |
+note: the lint level is defined here
+ --> $DIR/reference-links.rs:2:9
+ |
+LL | #![deny(broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: unresolved link to `std::process::Comman`
+ --> $DIR/reference-links.rs:5:10
+ |
+LL | //! [a]: std::process::Comman
+ | ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process`
+
+error: aborting due to 2 previous errors
+
+// ignore-tidy-linelength
// edition:2018
-#![feature(min_const_generics)]
-
// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>'
pub async fn foo() -> Option<Foo> {
None
pub async fn mut_self(mut self, mut first: usize) {}
}
+pub trait Pattern<'a> {}
+
pub trait Trait<const N: usize> {}
// @has async_fn/fn.const_generics.html
// @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
+
+// test that elided lifetimes are properly elided and not displayed as `'_`
+// regression test for #63037
+// @has async_fn/fn.elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
+pub async fn elided(foo: &str) -> &str {}
+// This should really be shown as written, but for implementation reasons it's difficult.
+// See `impl Clean for TyKind::Rptr`.
+// @has async_fn/fn.user_elided.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
+pub async fn user_elided(foo: &'_ str) -> &str {}
+// @has async_fn/fn.static_trait.html
+// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
+pub async fn static_trait(foo: &str) -> Box<dyn Bar> {}
+// @has async_fn/fn.lifetime_for_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
+pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {}
+// @has async_fn/fn.elided_in_input_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
+pub async fn elided_in_input_trait(t: impl Pattern<'_>) {}
+
+struct AsyncFdReadyGuard<'a, T> { x: &'a T }
+
+impl Foo {
+ // @has async_fn/struct.Foo.html
+ // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+ pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
+ // taken from `tokio` as an example of a method that was particularly bad before
+ // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+ pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
+ // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)"
+ pub async fn mut_self(&mut self) {}
+}
+
+// test named lifetimes, just in case
+// @has async_fn/fn.named.html
+// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
+pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {}
+// @has async_fn/fn.named_trait.html
+// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
+pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {}
#![crate_name = "foo"]
-// ignore-tidy-linelength
-
-// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This example deliberately fails to compile"
-// @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "This example is not tested"
-// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]/span' "This example panics"
+// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ"
/// foo
///
/// hoo();
/// ```
///
-/// ```
+/// ```edition2018
/// let x = 0;
/// ```
pub fn bar() -> usize { 2 }
// edition:2018
-#![feature(min_const_generics)]
-
pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]> {
[[0; N]; N].iter().copied()
}
// edition:2018
// aux-build: extern_crate.rs
-#![feature(min_const_generics)]
#![crate_name = "foo"]
extern crate extern_crate;
// ignore-tidy-linelength
-#![feature(min_const_generics)]
#![crate_name = "foo"]
// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];'
--- /dev/null
+// ignore-tidy-linelength
+#![crate_name = "foo"]
+#![deny(broken_intra_doc_links)]
+
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+//! [slice::rotate_left]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
+//! [array::map]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*::is_null'
+//! [pointer::is_null]
+//! [*const::is_null]
+//! [*mut::is_null]
+//! [*::is_null]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
+//! [unit]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
+//! [tuple]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
+//! [reference]
+//! [&]
+//! [&mut]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
+//! [fn]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
+//! [never]
+//! [!]
// Reject mixing cyclic structure and Drop when using TypedArena.
//
-// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+// (Compare against dropck-vec-cycle-checked.rs)
//
-// (Also compare against compile-fail/dropck_tarena_unsound_drop.rs,
+// (Also compare against ui-fulldeps/dropck-tarena-unsound-drop.rs,
// which is a reduction of this code to more directly show the reason
// for the error message we see here.)
// methods might access borrowed data, as long as the borrowed data
// has lifetime that strictly outlives the arena itself.
//
-// Compare against compile-fail/dropck_tarena_unsound_drop.rs, which
+// Compare against ui-fulldeps/dropck-tarena-unsound-drop.rs, which
// shows a similar setup, but restricts `f` so that the struct `C<'a>`
// is force-fed a lifetime equal to that of the borrowed arena.
fn drop(&mut self) {
println!("Dropping {}", self.0);
let old = LOG.load(Ordering::SeqCst);
- LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+ let _ = LOG.compare_exchange(
+ old,
+ old << 4 | self.0 as usize,
+ Ordering::SeqCst,
+ Ordering::SeqCst
+ );
}
}
fn drop(&mut self) {
println!("Dropping {}", self.0);
let old = LOG.load(Ordering::SeqCst);
- LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+ let _ = LOG.compare_exchange(
+ old,
+ old << 4 | self.0 as usize,
+ Ordering::SeqCst,
+ Ordering::SeqCst
+ );
}
}
// Ensure that we can copy out of a fixed-size array.
//
-// (Compare with compile-fail/move-out-of-array-1.rs)
+// (Compare with ui/moves/move-out-of-array-1.rs)
#[derive(Copy, Clone)]
struct C { _x: u8 }
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error[E0308]: mismatched types
--> $DIR/match_arr_unknown_len.rs:6:9
fn drop(&mut self) {
println!("Dropping {}", self.0);
let old = LOG.load(Ordering::SeqCst);
- LOG.compare_and_swap(old, old << 4 | self.0 as usize, Ordering::SeqCst);
+ let _ = LOG.compare_exchange(
+ old,
+ old << 4 | self.0 as usize,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ );
}
}
pub fn test<A: Foo, B: Foo>() {
let _array: [u32; <A as Foo>::Y];
- //~^ ERROR the trait bound `A: Foo` is not satisfied [E0277]
+ //~^ ERROR generic parameters may not be used
}
-fn main() {
-}
+fn main() {}
-error[E0277]: the trait bound `A: Foo` is not satisfied
- --> $DIR/associated-const-type-parameter-arrays.rs:16:23
+error: generic parameters may not be used in const operations
+ --> $DIR/associated-const-type-parameter-arrays.rs:16:24
|
-LL | const Y: usize;
- | --------------- required by `Foo::Y`
-...
LL | let _array: [u32; <A as Foo>::Y];
- | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A`
+ | ^ cannot perform const operation using `A`
|
-help: consider further restricting this bound
- |
-LL | pub fn test<A: Foo + Foo, B: Foo>() {
- | ^^^^^
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
struct Foo<A: Adapter> {
adapter: A,
links: [u32; A::LINKS], // Shouldn't suggest bounds already there.
- //~^ ERROR: no associated item named `LINKS` found
+ //~^ ERROR generic parameters may not be used in const operations
}
fn main() {}
-error[E0599]: no associated item named `LINKS` found for type parameter `A` in the current scope
- --> $DIR/associated-item-duplicate-bounds.rs:7:21
+error: generic parameters may not be used in const operations
+ --> $DIR/associated-item-duplicate-bounds.rs:7:18
|
LL | links: [u32; A::LINKS], // Shouldn't suggest bounds already there.
- | ^^^^^ associated item not found in `A`
+ | ^^^^^^^^ cannot perform const operation using `A`
|
- = help: items from traits can only be used if the type parameter is bounded by the trait
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0599`.
// the trait definition if there is no default method and for every impl,
// `Self` does implement `Get`.
//
-// See also compile-fail tests associated-types-no-suitable-supertrait
+// See also tests associated-types-no-suitable-supertrait
// and associated-types-no-suitable-supertrait-2, which show how small
// variants of the code below can fail.
// ...but not in an impl that redefines one of the types.
impl Tr for bool {
type A = Box<Self::B>;
- //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
+ //~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
}
// (the error is shown twice for some reason)
impl Tr for usize {
type B = &'static Self::A;
- //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
+ //~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
}
fn main() {
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
+error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
--> $DIR/defaults-cyclic-fail-1.rs:26:5
|
LL | type A = Box<Self::B>;
- | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
+error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
--> $DIR/defaults-cyclic-fail-1.rs:32:5
|
LL | type B = &'static Self::A;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0275`.
impl Tr for bool {
type A = Box<Self::B>;
- //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
+ //~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
}
// (the error is shown twice for some reason)
impl Tr for usize {
type B = &'static Self::A;
- //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
+ //~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
}
fn main() {
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
+error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
--> $DIR/defaults-cyclic-fail-2.rs:27:5
|
LL | type A = Box<Self::B>;
- | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
+error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
--> $DIR/defaults-cyclic-fail-2.rs:33:5
|
LL | type B = &'static Self::A;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0275`.
LL | type Ty = Vec<[u8]>;
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
- ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
+ ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| - required by this bound in `Vec`
--- /dev/null
+// Regression test for #79714
+
+trait Baz {}
+impl Baz for () {}
+impl<T> Baz for (T,) {}
+
+trait Fiz {}
+impl Fiz for bool {}
+
+trait Grault {
+ type A;
+ type B;
+}
+
+impl<T: Grault> Grault for (T,)
+where
+ Self::A: Baz,
+ Self::B: Fiz,
+{
+ type A = ();
+ //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ type B = bool;
+ //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+}
+//~^^^^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+
+fn main() {
+ let x: <(_,) as Grault>::A = ();
+}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-1.rs:15:1
+ |
+LL | / impl<T: Grault> Grault for (T,)
+LL | | where
+LL | | Self::A: Baz,
+LL | | Self::B: Fiz,
+... |
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+ = note: 1 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-1.rs:20:5
+ |
+LL | type A = ();
+ | ^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+ = note: 1 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-1.rs:22:5
+ |
+LL | type B = bool;
+ | ^^^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+ = note: 1 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
--- /dev/null
+// Regression test for #79714
+
+trait Grault {
+ type A;
+}
+
+impl<T: Grault> Grault for (T,)
+where
+ Self::A: Copy,
+{
+ type A = ();
+ //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+}
+//~^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+
+fn main() {}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-2.rs:7:1
+ |
+LL | / impl<T: Grault> Grault for (T,)
+LL | | where
+LL | | Self::A: Copy,
+LL | | {
+LL | | type A = ();
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-2.rs:11:5
+ |
+LL | type A = ();
+ | ^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
--- /dev/null
+#![feature(associated_type_defaults)]
+
+use std::ops::Index;
+
+trait Hierarchy {
+ type Value;
+ type ChildKey;
+ type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>;
+ //~^ ERROR: the value of the associated types
+
+ fn data(&self) -> Option<(Self::Value, Self::Children)>;
+}
+
+fn main() {}
--- /dev/null
+error[E0191]: the value of the associated types `ChildKey` (from trait `Hierarchy`), `Children` (from trait `Hierarchy`), `Value` (from trait `Hierarchy`) must be specified
+ --> $DIR/issue-23595-1.rs:8:58
+ |
+LL | type Value;
+ | ----------- `Value` defined here
+LL | type ChildKey;
+ | -------------- `ChildKey` defined here
+LL | type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>;
+ | -----------------------------------------------------^^^^^^^^^--
+ | | |
+ | | help: specify the associated types: `Hierarchy<Value = Type, ChildKey = Type, Children = Type>`
+ | `Children` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0191`.
--- /dev/null
+/// The compiler previously did not properly check the bound of `From` when it was used from type
+/// of the dyn trait object (use in `copy_any` below). Since the associated type is under user
+/// control in this usage, the compiler could be tricked to believe any type implemented any trait.
+/// This would ICE, except for pure marker traits like `Copy`. It did not require providing an
+/// instance of the dyn trait type, only name said type.
+trait Setup {
+ type From: Copy;
+}
+
+fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+ *from
+}
+
+pub fn copy_any<T>(t: &T) -> T {
+ copy::<dyn Setup<From=T>>(t)
+ //~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `T: Copy` is not satisfied
+ --> $DIR/issue-27675-unchecked-bounds.rs:15:31
+ |
+LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+ | ----- required by this bound in `copy`
+...
+LL | copy::<dyn Setup<From=T>>(t)
+ | ^ the trait `Copy` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | pub fn copy_any<T: Copy>(t: &T) -> T {
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
error[E0573]: expected type, found built-in attribute `feature`
- --> $DIR/issue-78654.rs:10:15
+ --> $DIR/issue-78654.rs:9:15
|
LL | impl<const H: feature> Foo {
| ^^^^^^^ not a type
error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-78654.rs:10:12
+ --> $DIR/issue-78654.rs:9:12
|
LL | impl<const H: feature> Foo {
| ^ unconstrained const parameter
error[E0573]: expected type, found built-in attribute `feature`
- --> $DIR/issue-78654.rs:10:15
+ --> $DIR/issue-78654.rs:9:15
|
LL | impl<const H: feature> Foo {
| ^^^^^^^ not a type
error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-78654.rs:10:12
+ --> $DIR/issue-78654.rs:9:12
|
LL | impl<const H: feature> Foo {
| ^ unconstrained const parameter
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo;
LL | let x: Vec<dyn Trait + Sized> = Vec::new();
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
- ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
+ ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| - required by this bound in `Vec`
--- /dev/null
+error[E0158]: const parameters cannot be referenced in patterns
+ --> $DIR/const-param.rs:8:9
+ |
+LL | N => {}
+ | ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0158`.
--- /dev/null
+error[E0158]: const parameters cannot be referenced in patterns
+ --> $DIR/const-param.rs:8:9
+ |
+LL | N => {}
+ | ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0158`.
// Identifier pattern referring to a const generic parameter is an error (issue #68853).
-
-#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
fn check<const N: usize>() {
match 1 {
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/const-param.rs:3:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
-
-error[E0158]: const parameters cannot be referenced in patterns
- --> $DIR/const-param.rs:7:9
- |
-LL | N => {}
- | ^
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0158`.
--> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30
|
LL | _ => { addr.push(&mut x); }
- | ^^^^^^ mutable borrow starts here in previous iteration of loop
+ | ^^^^^^ `x` was mutably borrowed here in the previous iteration of the loop
error: aborting due to 3 previous errors
LL | (self.func)(arg)
| ------------^^^-
| | |
- | | mutable borrow starts here in previous iteration of loop
+ | | `*arg` was mutably borrowed here in the previous iteration of the loop
| argument requires that `*arg` is borrowed for `'a`
error[E0499]: cannot borrow `*arg` as mutable more than once at a time
LL | (self.func)(arg)
| ------------^^^-
| | |
- | | mutable borrow starts here in previous iteration of loop
+ | | `*arg` was mutably borrowed here in the previous iteration of the loop
| argument requires that `*arg` is borrowed for `'a`
error[E0499]: cannot borrow `*arg` as mutable more than once at a time
LL | (self.func)(arg)
| ------------^^^-
| | |
- | | mutable borrow starts here in previous iteration of loop
+ | | `*arg` was mutably borrowed here in the previous iteration of the loop
| argument requires that `*arg` is borrowed for `'a`
error: aborting due to 3 previous errors; 1 warning emitted
--> $DIR/two-phase-across-loop.rs:17:22
|
LL | strings.push(foo.get_string());
- | ^^^ mutable borrow starts here in previous iteration of loop
+ | ^^^ `foo` was mutably borrowed here in the previous iteration of the loop
error: aborting due to previous error
--- /dev/null
+fn main() {
+ let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
+ //~^ ERROR E0133
+ let _: unsafe fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK
+}
--- /dev/null
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/coerce-unsafe-closure-to-unsafe-fn-ptr.rs:2:31
+ |
+LL | let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+fn main() {
+ let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
+ //~^ ERROR E0277
+}
--- /dev/null
+error[E0277]: expected a `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+ --> $DIR/coerce-unsafe-to-closure.rs:2:44
+ |
+LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
+ | ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+ |
+ = help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Trait {}
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:12:32
+ --> $DIR/argument_order.rs:11:32
|
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
| -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>`
error[E0747]: lifetime provided when a type was expected
- --> $DIR/argument_order.rs:20:23
+ --> $DIR/argument_order.rs:19:23
|
LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
| ^^^^^^^
error: type parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:6:28
+ --> $DIR/argument_order.rs:5:28
|
LL | struct Bad<const N: usize, T> {
| -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:12:32
+ --> $DIR/argument_order.rs:11:32
|
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
| -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
error: type parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:12:36
+ --> $DIR/argument_order.rs:11:36
|
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
| ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
error[E0747]: lifetime provided when a type was expected
- --> $DIR/argument_order.rs:20:23
+ --> $DIR/argument_order.rs:19:23
|
LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
| ^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Bad<const N: usize, T> {
//[min]~^ ERROR type parameters must be declared prior to const parameters
error: constant expression depends on a generic parameter
- --> $DIR/array-size-in-generic-struct-param.rs:9:38
+ --> $DIR/array-size-in-generic-struct-param.rs:8:38
|
LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
| ^^^^^^^^^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/array-size-in-generic-struct-param.rs:20:10
+ --> $DIR/array-size-in-generic-struct-param.rs:19:10
|
LL | arr: [u8; CFG.arr_size],
| ^^^^^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/array-size-in-generic-struct-param.rs:9:48
+ --> $DIR/array-size-in-generic-struct-param.rs:8:48
|
LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/array-size-in-generic-struct-param.rs:20:15
+ --> $DIR/array-size-in-generic-struct-param.rs:19:15
|
LL | arr: [u8; CFG.arr_size],
| ^^^ cannot perform const operation using `CFG`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: `Config` is forbidden as the type of a const generic parameter
- --> $DIR/array-size-in-generic-struct-param.rs:18:21
+ --> $DIR/array-size-in-generic-struct-param.rs:17:21
|
LL | struct B<const CFG: Config> {
| ^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[allow(dead_code)]
struct ArithArrayLen<const N: usize>([u32; 0 + N]);
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![allow(dead_code)]
error[E0277]: the trait bound `u16: Bar<N>` is not satisfied
- --> $DIR/associated-type-bound-fail.rs:14:5
+ --> $DIR/associated-type-bound-fail.rs:13:5
|
LL | type Assoc: Bar<N>;
| ------ required by this bound in `Foo::Assoc`
error[E0277]: the trait bound `u16: Bar<N>` is not satisfied
- --> $DIR/associated-type-bound-fail.rs:14:5
+ --> $DIR/associated-type-bound-fail.rs:13:5
|
LL | type Assoc: Bar<N>;
| ------ required by this bound in `Foo::Assoc`
// revisions: full min
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Bar<const N: usize> {}
// revisions: full min
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Bar<const N: usize> {}
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct Struct<const N: usize>(pub [u8; N]);
// edition:2018
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub trait Foo<const N: usize> {}
struct Local;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct Num<const N: usize>;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub trait Foo {
fn foo(&self);
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::fmt::Debug;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
// This test confirms that the types can be inferred correctly for this example with const
// generics. Previously this would ICE, and more recently error.
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/closing-args-token.rs:11:9
+ --> $DIR/closing-args-token.rs:10:9
|
LL | S::<5 + 2 >> 7>;
| ^^^^^
| ^ ^
error: comparison operators cannot be chained
- --> $DIR/closing-args-token.rs:11:16
+ --> $DIR/closing-args-token.rs:10:16
|
LL | S::<5 + 2 >> 7>;
| ^ ^
| ^^^^
error: comparison operators cannot be chained
- --> $DIR/closing-args-token.rs:17:20
+ --> $DIR/closing-args-token.rs:16:20
|
LL | S::<{ 5 + 2 } >> 7>;
| ^ ^
| ^^^^
error: expected expression, found `;`
- --> $DIR/closing-args-token.rs:22:16
+ --> $DIR/closing-args-token.rs:21:16
|
LL | T::<0 >= 3>;
| ^ expected expression
error: comparison operators cannot be chained
- --> $DIR/closing-args-token.rs:28:12
+ --> $DIR/closing-args-token.rs:27:12
|
LL | T::<x >>= 2 > 0>;
| ^^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/closing-args-token.rs:11:9
+ --> $DIR/closing-args-token.rs:10:9
|
LL | S::<5 + 2 >> 7>;
| ^^^^^
| ^ ^
error: comparison operators cannot be chained
- --> $DIR/closing-args-token.rs:11:16
+ --> $DIR/closing-args-token.rs:10:16
|
LL | S::<5 + 2 >> 7>;
| ^ ^
| ^^^^
error: comparison operators cannot be chained
- --> $DIR/closing-args-token.rs:17:20
+ --> $DIR/closing-args-token.rs:16:20
|
LL | S::<{ 5 + 2 } >> 7>;
| ^ ^
| ^^^^
error: expected expression, found `;`
- --> $DIR/closing-args-token.rs:22:16
+ --> $DIR/closing-args-token.rs:21:16
|
LL | T::<0 >= 3>;
| ^ expected expression
error: comparison operators cannot be chained
- --> $DIR/closing-args-token.rs:28:12
+ --> $DIR/closing-args-token.rs:27:12
|
LL | T::<x >>= 2 > 0>;
| ^^ ^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct S<const X: u32>;
struct T<const X: bool>;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const N: usize>(v: &[u8; N]) -> &[u8] {
v
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: usize>; // ok
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct A<const N: u32>;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait IsZeroTrait<const IS_ZERO: bool>{}
error: generic parameters may not be used in const operations
- --> $DIR/const-arg-in-const-arg.rs:14:23
+ --> $DIR/const-arg-in-const-arg.rs:13:23
|
LL | let _: [u8; foo::<T>()];
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/const-arg-in-const-arg.rs:15:23
+ --> $DIR/const-arg-in-const-arg.rs:14:23
|
LL | let _: [u8; bar::<N>()];
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/const-arg-in-const-arg.rs:25:23
+ --> $DIR/const-arg-in-const-arg.rs:24:23
|
LL | let _ = [0; bar::<N>()];
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/const-arg-in-const-arg.rs:30:24
+ --> $DIR/const-arg-in-const-arg.rs:29:24
|
LL | let _: Foo<{ foo::<T>() }>;
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/const-arg-in-const-arg.rs:31:24
+ --> $DIR/const-arg-in-const-arg.rs:30:24
|
LL | let _: Foo<{ bar::<N>() }>;
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/const-arg-in-const-arg.rs:36:27
+ --> $DIR/const-arg-in-const-arg.rs:35:27
|
LL | let _ = Foo::<{ foo::<T>() }>;
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/const-arg-in-const-arg.rs:37:27
+ --> $DIR/const-arg-in-const-arg.rs:36:27
|
LL | let _ = Foo::<{ bar::<N>() }>;
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:16:23
+ --> $DIR/const-arg-in-const-arg.rs:15:23
|
LL | let _: [u8; faz::<'a>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:17:23
+ --> $DIR/const-arg-in-const-arg.rs:16:23
|
LL | let _: [u8; baz::<'a>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:18:23
+ --> $DIR/const-arg-in-const-arg.rs:17:23
|
LL | let _: [u8; faz::<'b>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:19:23
+ --> $DIR/const-arg-in-const-arg.rs:18:23
|
LL | let _: [u8; baz::<'b>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:26:23
+ --> $DIR/const-arg-in-const-arg.rs:25:23
|
LL | let _ = [0; faz::<'a>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:27:23
+ --> $DIR/const-arg-in-const-arg.rs:26:23
|
LL | let _ = [0; baz::<'a>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:28:23
+ --> $DIR/const-arg-in-const-arg.rs:27:23
|
LL | let _ = [0; faz::<'b>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:29:23
+ --> $DIR/const-arg-in-const-arg.rs:28:23
|
LL | let _ = [0; baz::<'b>(&())];
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:32:24
+ --> $DIR/const-arg-in-const-arg.rs:31:24
|
LL | let _: Foo<{ faz::<'a>(&()) }>;
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:33:24
+ --> $DIR/const-arg-in-const-arg.rs:32:24
|
LL | let _: Foo<{ baz::<'a>(&()) }>;
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:34:24
+ --> $DIR/const-arg-in-const-arg.rs:33:24
|
LL | let _: Foo<{ faz::<'b>(&()) }>;
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:35:24
+ --> $DIR/const-arg-in-const-arg.rs:34:24
|
LL | let _: Foo<{ baz::<'b>(&()) }>;
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:38:27
+ --> $DIR/const-arg-in-const-arg.rs:37:27
|
LL | let _ = Foo::<{ faz::<'a>(&()) }>;
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:39:27
+ --> $DIR/const-arg-in-const-arg.rs:38:27
|
LL | let _ = Foo::<{ baz::<'a>(&()) }>;
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:40:27
+ --> $DIR/const-arg-in-const-arg.rs:39:27
|
LL | let _ = Foo::<{ faz::<'b>(&()) }>;
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/const-arg-in-const-arg.rs:41:27
+ --> $DIR/const-arg-in-const-arg.rs:40:27
|
LL | let _ = Foo::<{ baz::<'b>(&()) }>;
| ^^
// FIXME(const_generics): This test currently causes an ICE because
// we don't yet correctly deal with lifetimes, reenable this test once
// this is fixed.
-#![cfg_attr(min, feature(min_const_generics))]
const fn foo<T>() -> usize { std::mem::size_of::<T>() }
const fn bar<const N: usize>() -> usize { N }
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn const_u32_identity<const X: u32>() -> u32 {
X
error[E0747]: constant provided when a type was expected
- --> $DIR/const-arg-type-arg-misordered.rs:8:35
+ --> $DIR/const-arg-type-arg-misordered.rs:7:35
|
LL | fn foo<const N: usize>() -> Array<N, ()> {
| ^
error[E0747]: constant provided when a type was expected
- --> $DIR/const-arg-type-arg-misordered.rs:8:35
+ --> $DIR/const-arg-type-arg-misordered.rs:7:35
|
LL | fn foo<const N: usize>() -> Array<N, ()> {
| ^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
type Array<T, const N: usize> = [T; N];
error[E0277]: the size for values of type `T` cannot be known at compilation time
- --> $DIR/const-argument-if-length.rs:8:28
+ --> $DIR/const-argument-if-length.rs:7:28
|
LL | pub const fn is_zst<T: ?Sized>() -> usize {
| - this type parameter needs to be `Sized`
| - required by this bound in `std::mem::size_of`
error[E0277]: the size for values of type `T` cannot be known at compilation time
- --> $DIR/const-argument-if-length.rs:17:12
+ --> $DIR/const-argument-if-length.rs:16:12
|
LL | pub struct AtLeastByte<T: ?Sized> {
| - this type parameter needs to be `Sized`
error: generic parameters may not be used in const operations
- --> $DIR/const-argument-if-length.rs:19:24
+ --> $DIR/const-argument-if-length.rs:18:24
|
LL | pad: [u8; is_zst::<T>()],
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0277]: the size for values of type `T` cannot be known at compilation time
- --> $DIR/const-argument-if-length.rs:17:12
+ --> $DIR/const-argument-if-length.rs:16:12
|
LL | pub struct AtLeastByte<T: ?Sized> {
| - this type parameter needs to be `Sized`
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
pub const fn is_zst<T: ?Sized>() -> usize {
if std::mem::size_of::<T>() == 0 {
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-parameter.rs:16:20
+ --> $DIR/const-expression-parameter.rs:15:20
|
LL | i32_identity::<1 + 2>();
| ^^^^^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-parameter.rs:16:20
+ --> $DIR/const-expression-parameter.rs:15:20
|
LL | i32_identity::<1 + 2>();
| ^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn i32_identity<const X: i32>() -> i32 {
5
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
const fn const_u32_identity<const X: u32>() -> u32 {
X
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo<T, const N: usize>([T; N]);
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[derive(Debug)]
struct S<const N: usize>;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo<const A: usize, const B: usize>;
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/const-param-before-other-params.rs:6:21
+ --> $DIR/const-param-before-other-params.rs:5:21
|
LL | fn bar<const X: (), 'a>(_: &'a ()) {
| --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: ()>`
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/const-param-before-other-params.rs:6:21
+ --> $DIR/const-param-before-other-params.rs:5:21
|
LL | fn bar<const X: (), 'a>(_: &'a ()) {
| --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
error: type parameters must be declared prior to const parameters
- --> $DIR/const-param-before-other-params.rs:11:21
+ --> $DIR/const-param-before-other-params.rs:10:21
|
LL | fn foo<const X: (), T>(_: &T) {}
| --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
error: `()` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-before-other-params.rs:6:17
+ --> $DIR/const-param-before-other-params.rs:5:17
|
LL | fn bar<const X: (), 'a>(_: &'a ()) {
| ^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `()` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-before-other-params.rs:11:17
+ --> $DIR/const-param-before-other-params.rs:10:17
|
LL | fn foo<const X: (), T>(_: &T) {}
| ^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn bar<const X: (), 'a>(_: &'a ()) {
//~^ ERROR lifetime parameters must be declared prior to const parameters
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:11:19
+ --> $DIR/const-param-elided-lifetime.rs:10:19
|
LL | struct A<const N: &u8>;
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:16:15
+ --> $DIR/const-param-elided-lifetime.rs:15:15
|
LL | impl<const N: &u8> A<N> {
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:19:21
+ --> $DIR/const-param-elided-lifetime.rs:18:21
|
LL | fn foo<const M: &u8>(&self) {}
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:24:15
+ --> $DIR/const-param-elided-lifetime.rs:23:15
|
LL | impl<const N: &u8> B for A<N> {}
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:28:17
+ --> $DIR/const-param-elided-lifetime.rs:27:17
|
LL | fn bar<const N: &u8>() {}
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:11:19
+ --> $DIR/const-param-elided-lifetime.rs:10:19
|
LL | struct A<const N: &u8>;
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:16:15
+ --> $DIR/const-param-elided-lifetime.rs:15:15
|
LL | impl<const N: &u8> A<N> {
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:19:21
+ --> $DIR/const-param-elided-lifetime.rs:18:21
|
LL | fn foo<const M: &u8>(&self) {}
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:24:15
+ --> $DIR/const-param-elided-lifetime.rs:23:15
|
LL | impl<const N: &u8> B for A<N> {}
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
- --> $DIR/const-param-elided-lifetime.rs:28:17
+ --> $DIR/const-param-elided-lifetime.rs:27:17
|
LL | fn bar<const N: &u8>() {}
| ^ explicit lifetime name needed here
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:11:19
+ --> $DIR/const-param-elided-lifetime.rs:10:19
|
LL | struct A<const N: &u8>;
| ^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:16:15
+ --> $DIR/const-param-elided-lifetime.rs:15:15
|
LL | impl<const N: &u8> A<N> {
| ^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:24:15
+ --> $DIR/const-param-elided-lifetime.rs:23:15
|
LL | impl<const N: &u8> B for A<N> {}
| ^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:28:17
+ --> $DIR/const-param-elided-lifetime.rs:27:17
|
LL | fn bar<const N: &u8>() {}
| ^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-elided-lifetime.rs:19:21
+ --> $DIR/const-param-elided-lifetime.rs:18:21
|
LL | fn foo<const M: &u8>(&self) {}
| ^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: &u8>;
//~^ ERROR `&` without an explicit lifetime name cannot be used here
error[E0401]: can't use generic parameters from outer function
- --> $DIR/const-param-from-outer-fn.rs:9:9
+ --> $DIR/const-param-from-outer-fn.rs:8:9
|
LL | fn foo<const X: u32>() {
| - const parameter from outer function
error[E0401]: can't use generic parameters from outer function
- --> $DIR/const-param-from-outer-fn.rs:9:9
+ --> $DIR/const-param-from-outer-fn.rs:8:9
|
LL | fn foo<const X: u32>() {
| - const parameter from outer function
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const X: u32>() {
fn bar() -> u32 {
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
macro_rules! bar {
($($t:tt)*) => { impl<const N: usize> $($t)* };
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
async fn foo<const N: usize>(arg: [u8; N]) -> usize { arg.len() }
+++ /dev/null
-trait Trait<const T: ()> {} //~ ERROR const generics are unstable
-
-fn main() {}
+++ /dev/null
-error[E0658]: const generics are unstable
- --> $DIR/const-param-in-trait-ungated.rs:1:19
- |
-LL | trait Trait<const T: ()> {}
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Trait<const T: u8> {}
-#![feature(min_const_generics)]
-
type N = u32;
struct Foo<const M: usize>;
fn test<const N: usize>() -> Foo<N> { //~ ERROR type provided when
error[E0747]: type provided when a constant was expected
- --> $DIR/const-param-shadowing.rs:5:34
+ --> $DIR/const-param-shadowing.rs:3:34
|
LL | fn test<const N: usize>() -> Foo<N> {
| ^
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/const-param-type-depends-on-const-param.rs:12:52
+ --> $DIR/const-param-type-depends-on-const-param.rs:11:52
|
LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
| ^ the type must not depend on the parameter `N`
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/const-param-type-depends-on-const-param.rs:16:40
+ --> $DIR/const-param-type-depends-on-const-param.rs:15:40
|
LL | pub struct SelfDependent<const N: [u8; N]>;
| ^ the type must not depend on the parameter `N`
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/const-param-type-depends-on-const-param.rs:12:52
+ --> $DIR/const-param-type-depends-on-const-param.rs:11:52
|
LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
| ^ the type must not depend on the parameter `N`
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/const-param-type-depends-on-const-param.rs:16:40
+ --> $DIR/const-param-type-depends-on-const-param.rs:15:40
|
LL | pub struct SelfDependent<const N: [u8; N]>;
| ^ the type must not depend on the parameter `N`
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-type-depends-on-const-param.rs:12:47
+ --> $DIR/const-param-type-depends-on-const-param.rs:11:47
|
LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
| ^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/const-param-type-depends-on-const-param.rs:16:35
+ --> $DIR/const-param-type-depends-on-const-param.rs:15:35
|
LL | pub struct SelfDependent<const N: [u8; N]>;
| ^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
// Currently, const parameters cannot depend on other generic parameters,
// as our current implementation can't really support this.
use std::marker::PhantomData;
-struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
+struct B<T, const N: T>(PhantomData<[T; N]>);
//~^ ERROR the type of const parameters must not depend on other generic parameters
fn main() {}
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
| ^ the type must not depend on the parameter `T`
-error[E0658]: const generics are unstable
- --> $DIR/const-param-type-depends-on-type-param-ungated.rs:6:19
- |
-LL | struct B<T, const N: T>(PhantomData<[T; N]>);
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0658, E0770.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0770`.
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/const-param-type-depends-on-type-param.rs:12:34
+ --> $DIR/const-param-type-depends-on-type-param.rs:11:34
|
LL | pub struct Dependent<T, const X: T>([(); X]);
| ^ the type must not depend on the parameter `T`
error[E0392]: parameter `T` is never used
- --> $DIR/const-param-type-depends-on-type-param.rs:12:22
+ --> $DIR/const-param-type-depends-on-type-param.rs:11:22
|
LL | pub struct Dependent<T, const X: T>([(); X]);
| ^ unused parameter
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/const-param-type-depends-on-type-param.rs:12:34
+ --> $DIR/const-param-type-depends-on-type-param.rs:11:34
|
LL | pub struct Dependent<T, const X: T>([(); X]);
| ^ the type must not depend on the parameter `T`
error[E0392]: parameter `T` is never used
- --> $DIR/const-param-type-depends-on-type-param.rs:12:22
+ --> $DIR/const-param-type-depends-on-type-param.rs:11:22
|
LL | pub struct Dependent<T, const X: T>([(); X]);
| ^ unused parameter
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
// Currently, const parameters cannot depend on other generic parameters,
// as our current implementation can't really support this.
error: const parameter `x` should have an upper case name
- --> $DIR/const-parameter-uppercase-lint.rs:9:15
+ --> $DIR/const-parameter-uppercase-lint.rs:8:15
|
LL | fn noop<const x: u32>() {
| ^ help: convert the identifier to upper case (notice the capitalization): `X`
|
note: the lint level is defined here
- --> $DIR/const-parameter-uppercase-lint.rs:7:9
+ --> $DIR/const-parameter-uppercase-lint.rs:6:9
|
LL | #![deny(non_upper_case_globals)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: const parameter `x` should have an upper case name
- --> $DIR/const-parameter-uppercase-lint.rs:9:15
+ --> $DIR/const-parameter-uppercase-lint.rs:8:15
|
LL | fn noop<const x: u32>() {
| ^ help: convert the identifier to upper case (notice the capitalization): `X`
|
note: the lint level is defined here
- --> $DIR/const-parameter-uppercase-lint.rs:7:9
+ --> $DIR/const-parameter-uppercase-lint.rs:6:9
|
LL | #![deny(non_upper_case_globals)]
| ^^^^^^^^^^^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![deny(non_upper_case_globals)]
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![allow(dead_code, unused_variables)]
error: constant expression depends on a generic parameter
- --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30
+ --> $DIR/feature-gate-const_evaluatable_checked.rs:8:30
|
LL | fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
| ^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33
+ --> $DIR/feature-gate-const_evaluatable_checked.rs:5:33
|
LL | type Arr<const N: usize> = [u8; N - 1];
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
type Arr<const N: usize> = [u8; N - 1];
//[min]~^ ERROR generic parameters may not be used in const operations
error: generic parameters may not be used in const operations
- --> $DIR/simple.rs:8:53
+ --> $DIR/simple.rs:7:53
|
LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/simple.rs:8:35
+ --> $DIR/simple.rs:7:35
|
LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
| ^ cannot perform const operation using `N`
// [full] run-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
#![feature(const_evaluatable_checked)]
#![allow(incomplete_features)]
error[E0080]: evaluation of constant value failed
- --> $DIR/simple_fail.rs:7:33
+ --> $DIR/simple_fail.rs:6:33
|
LL | type Arr<const N: usize> = [u8; N - 1];
| ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
error: generic parameters may not be used in const operations
- --> $DIR/simple_fail.rs:7:33
+ --> $DIR/simple_fail.rs:6:33
|
LL | type Arr<const N: usize> = [u8; N - 1];
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
#![feature(const_evaluatable_checked)]
#![allow(incomplete_features)]
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: u8>;
struct B<const N: u16>;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
extern crate crayte;
use crayte::*;
error: type parameters must be declared prior to const parameters
- --> $DIR/complex-unord-param.rs:9:41
+ --> $DIR/complex-unord-param.rs:8:41
|
LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
| ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a, const N: usize, const M: usize>`
// Checks a complicated usage of unordered params
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![allow(dead_code)]
struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/intermixed-lifetime.rs:7:28
+ --> $DIR/intermixed-lifetime.rs:6:28
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
| -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
error: lifetime parameters must be declared prior to type parameters
- --> $DIR/intermixed-lifetime.rs:11:37
+ --> $DIR/intermixed-lifetime.rs:10:37
|
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
| --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/intermixed-lifetime.rs:7:28
+ --> $DIR/intermixed-lifetime.rs:6:28
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
| -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
error: type parameters must be declared prior to const parameters
- --> $DIR/intermixed-lifetime.rs:7:32
+ --> $DIR/intermixed-lifetime.rs:6:32
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
| ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/intermixed-lifetime.rs:11:37
+ --> $DIR/intermixed-lifetime.rs:10:37
|
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
| --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
error: type parameters must be declared prior to const parameters
- --> $DIR/intermixed-lifetime.rs:11:28
+ --> $DIR/intermixed-lifetime.rs:10:28
|
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
| -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
// Checks that lifetimes cannot be interspersed between consts and types.
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
//~^ Error lifetime parameters must be declared prior to const parameters
error: type parameters must be declared prior to const parameters
- --> $DIR/needs-feature.rs:10:26
+ --> $DIR/needs-feature.rs:9:26
|
LL | struct A<const N: usize, T=u32>(T);
| -----------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
error: type parameters must be declared prior to const parameters
- --> $DIR/needs-feature.rs:10:26
+ --> $DIR/needs-feature.rs:9:26
|
LL | struct A<const N: usize, T=u32>(T);
- | -----------------^----- help: reorder the parameters: lifetimes, then types: `<T, const N: usize>`
+ | -----------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
-error[E0658]: const generics are unstable
- --> $DIR/needs-feature.rs:10:16
- |
-LL | struct A<const N: usize, T=u32>(T);
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
//[full] run-pass
// Verifies that having generic parameters after constants is not permitted without the
// `const_generics` feature.
-// revisions: none min full
+// revisions: min full
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: usize, T=u32>(T);
-//[none]~^ ERROR type parameters must be declared prior
-//[none]~| ERROR const generics are unstable
-//[min]~^^^ ERROR type parameters must be declared prior
+//[min]~^ ERROR type parameters must be declared prior
fn main() {
let _: A<3> = A(0);
error: type parameters must be declared prior to const parameters
- --> $DIR/simple-defaults.rs:9:40
+ --> $DIR/simple-defaults.rs:8:40
|
LL | struct FixedOutput<'a, const N: usize, T=u32> {
| ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>`
// Checks some basic test cases for defaults.
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![allow(dead_code)]
struct FixedOutput<'a, const N: usize, T=u32> {
error: type parameters with a default must be trailing
- --> $DIR/wrong-order.rs:5:10
+ --> $DIR/wrong-order.rs:4:10
|
LL | struct A<T = u32, const N: usize> {
| ^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: aborting due to previous error; 1 warning emitted
error: type parameters with a default must be trailing
- --> $DIR/wrong-order.rs:5:10
+ --> $DIR/wrong-order.rs:4:10
|
LL | struct A<T = u32, const N: usize> {
| ^
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
struct A<T = u32, const N: usize> {
//~^ ERROR type parameters with a default must be trailing
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[derive(Debug)]
struct X<const N: usize> {
error[E0308]: mismatched types
- --> $DIR/different_byref.rs:13:9
+ --> $DIR/different_byref.rs:12:9
|
LL | x = Const::<{ [4] }> {};
| ^^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
error: `[usize; 1]` is forbidden as the type of a const generic parameter
- --> $DIR/different_byref.rs:8:23
+ --> $DIR/different_byref.rs:7:23
|
LL | struct Const<const V: [usize; 1]> {}
| ^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Const<const V: [usize; 1]> {}
//[min]~^ ERROR `[usize; 1]` is forbidden
error[E0308]: mismatched types
- --> $DIR/different_byref_simple.rs:12:9
+ --> $DIR/different_byref_simple.rs:11:9
|
LL | u = ConstUsize::<4> {};
| ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
error[E0308]: mismatched types
- --> $DIR/different_byref_simple.rs:12:9
+ --> $DIR/different_byref_simple.rs:11:9
|
LL | u = ConstUsize::<4> {};
| ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct ConstUsize<const V: usize> {}
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Foo<const N: usize> {
fn myfun(&self) -> usize;
error[E0277]: the trait bound `(): Foo<N>` is not satisfied
- --> $DIR/exhaustive-value.rs:267:5
+ --> $DIR/exhaustive-value.rs:266:5
|
LL | fn test() {}
| --------- required by `Foo::test`
error[E0277]: the trait bound `(): Foo<N>` is not satisfied
- --> $DIR/exhaustive-value.rs:267:5
+ --> $DIR/exhaustive-value.rs:266:5
|
LL | fn test() {}
| --------- required by `Foo::test`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Foo<const N: u8> {
fn test() {}
error: using function pointers as const generic parameters is forbidden
- --> $DIR/fn-const-param-call.rs:12:25
+ --> $DIR/fn-const-param-call.rs:11:25
|
LL | struct Wrapper<const F: fn() -> u32>;
| ^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/fn-const-param-call.rs:14:15
+ --> $DIR/fn-const-param-call.rs:13:15
|
LL | impl<const F: fn() -> u32> Wrapper<F> {
| ^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/fn-const-param-call.rs:12:25
+ --> $DIR/fn-const-param-call.rs:11:25
|
LL | struct Wrapper<const F: fn() -> u32>;
| ^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/fn-const-param-call.rs:14:15
+ --> $DIR/fn-const-param-call.rs:13:15
|
LL | impl<const F: fn() -> u32> Wrapper<F> {
| ^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn function() -> u32 {
17
error: using function pointers as const generic parameters is forbidden
- --> $DIR/fn-const-param-infer.rs:7:25
+ --> $DIR/fn-const-param-infer.rs:6:25
|
LL | struct Checked<const F: fn(usize) -> bool>;
| ^^^^^^^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/fn-const-param-infer.rs:7:25
+ --> $DIR/fn-const-param-infer.rs:6:25
|
LL | struct Checked<const F: fn(usize) -> bool>;
| ^^^^^^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Checked<const F: fn(usize) -> bool>;
//~^ ERROR: using function pointers as const generic parameters
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::fmt::Display;
error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
- --> $DIR/forbid-non-structural_match-types.rs:15:19
+ --> $DIR/forbid-non-structural_match-types.rs:14:19
|
LL | struct D<const X: C>;
| ^ `C` doesn't derive both `PartialEq` and `Eq`
error: `A` is forbidden as the type of a const generic parameter
- --> $DIR/forbid-non-structural_match-types.rs:10:19
+ --> $DIR/forbid-non-structural_match-types.rs:9:19
|
LL | struct B<const X: A>; // ok
| ^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `C` is forbidden as the type of a const generic parameter
- --> $DIR/forbid-non-structural_match-types.rs:15:19
+ --> $DIR/forbid-non-structural_match-types.rs:14:19
|
LL | struct D<const X: C>;
| ^
= help: more complex types are supported with `#[feature(const_generics)]`
error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
- --> $DIR/forbid-non-structural_match-types.rs:15:19
+ --> $DIR/forbid-non-structural_match-types.rs:14:19
|
LL | struct D<const X: C>;
| ^ `C` doesn't derive both `PartialEq` and `Eq`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[derive(PartialEq, Eq)]
struct A;
error[E0044]: foreign items may not have const parameters
- --> $DIR/foreign-item-const-parameter.rs:8:5
+ --> $DIR/foreign-item-const-parameter.rs:7:5
|
LL | fn foo<const X: usize>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
= help: replace the const parameters with concrete consts
error[E0044]: foreign items may not have type or const parameters
- --> $DIR/foreign-item-const-parameter.rs:10:5
+ --> $DIR/foreign-item-const-parameter.rs:9:5
|
LL | fn bar<T, const X: usize>(_: T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
error[E0044]: foreign items may not have const parameters
- --> $DIR/foreign-item-const-parameter.rs:8:5
+ --> $DIR/foreign-item-const-parameter.rs:7:5
|
LL | fn foo<const X: usize>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
= help: replace the const parameters with concrete consts
error[E0044]: foreign items may not have type or const parameters
- --> $DIR/foreign-item-const-parameter.rs:10:5
+ --> $DIR/foreign-item-const-parameter.rs:9:5
|
LL | fn bar<T, const X: usize>(_: T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
extern "C" {
fn foo<const X: usize>(); //~ ERROR foreign items may not have const parameters
error: constant expression depends on a generic parameter
- --> $DIR/generic-function-call-in-array-length.rs:9:29
+ --> $DIR/generic-function-call-in-array-length.rs:8:29
|
LL | fn bar<const N: usize>() -> [u32; foo(N)] {
| ^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/generic-function-call-in-array-length.rs:9:39
+ --> $DIR/generic-function-call-in-array-length.rs:8:39
|
LL | fn bar<const N: usize>() -> [u32; foo(N)] {
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/generic-function-call-in-array-length.rs:12:13
+ --> $DIR/generic-function-call-in-array-length.rs:11:13
|
LL | [0; foo(N)]
| ^ cannot perform const operation using `N`
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
const fn foo(n: usize) -> usize { n * 2 }
error[E0308]: mismatched types
- --> $DIR/generic-param-mismatch.rs:7:5
+ --> $DIR/generic-param-mismatch.rs:6:5
|
LL | fn test<const N: usize, const M: usize>() -> [u8; M] {
| ------- expected `[u8; M]` because of return type
error[E0308]: mismatched types
- --> $DIR/generic-param-mismatch.rs:7:5
+ --> $DIR/generic-param-mismatch.rs:6:5
|
LL | fn test<const N: usize, const M: usize>() -> [u8; M] {
| ------- expected `[u8; M]` because of return type
// revisions: full min
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
fn test<const N: usize, const M: usize>() -> [u8; M] {
[0; N] //~ ERROR mismatched types
error: constant expression depends on a generic parameter
- --> $DIR/generic-sum-in-array-length.rs:7:45
+ --> $DIR/generic-sum-in-array-length.rs:6:45
|
LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
| ^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/generic-sum-in-array-length.rs:7:53
+ --> $DIR/generic-sum-in-array-length.rs:6:53
|
LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
| ^ cannot perform const operation using `A`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/generic-sum-in-array-length.rs:7:57
+ --> $DIR/generic-sum-in-array-length.rs:6:57
|
LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
| ^ cannot perform const operation using `B`
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
//[min]~^ ERROR generic parameters may not be used in const operations
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct S<const X: u32>;
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
- --> $DIR/impl-trait-with-const-arguments.rs:24:20
+ --> $DIR/impl-trait-with-const-arguments.rs:23:20
|
LL | assert_eq!(f::<4usize>(Usizable), 20usize);
| ^^^^^^ explicit generic argument not allowed
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
- --> $DIR/impl-trait-with-const-arguments.rs:24:20
+ --> $DIR/impl-trait-with-const-arguments.rs:23:20
|
LL | assert_eq!(f::<4usize>(Usizable), 20usize);
| ^^^^^^ explicit generic argument not allowed
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Usizer {
fn m(self) -> usize;
error[E0107]: wrong number of const arguments: expected 2, found 1
- --> $DIR/incorrect-number-of-const-args.rs:12:5
+ --> $DIR/incorrect-number-of-const-args.rs:11:5
|
LL | foo::<0>();
| ^^^^^^^^ expected 2 const arguments
error[E0107]: wrong number of const arguments: expected 2, found 3
- --> $DIR/incorrect-number-of-const-args.rs:13:17
+ --> $DIR/incorrect-number-of-const-args.rs:12:17
|
LL | foo::<0, 0, 0>();
| ^ unexpected const argument
error[E0107]: wrong number of const arguments: expected 2, found 1
- --> $DIR/incorrect-number-of-const-args.rs:12:5
+ --> $DIR/incorrect-number-of-const-args.rs:11:5
|
LL | foo::<0>();
| ^^^^^^^^ expected 2 const arguments
error[E0107]: wrong number of const arguments: expected 2, found 3
- --> $DIR/incorrect-number-of-const-args.rs:13:17
+ --> $DIR/incorrect-number-of-const-args.rs:12:17
|
LL | foo::<0, 0, 0>();
| ^ unexpected const argument
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const X: usize, const Y: usize>() -> usize {
0
error[E0282]: type annotations needed
- --> $DIR/cannot-infer-const-args.rs:12:5
+ --> $DIR/cannot-infer-const-args.rs:11:5
|
LL | foo();
| ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
error[E0282]: type annotations needed
- --> $DIR/cannot-infer-const-args.rs:12:5
+ --> $DIR/cannot-infer-const-args.rs:11:5
|
LL | foo();
| ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const X: usize>() -> usize {
0
-#![feature(min_const_generics)]
-
use std::convert::TryInto;
fn take_array_from_mut<T, const N: usize>(data: &mut [T], start: usize) -> &mut [T; N] {
error[E0282]: type annotations needed
- --> $DIR/issue-77092.rs:13:26
+ --> $DIR/issue-77092.rs:11:26
|
LL | println!("{:?}", take_array_from_mut(&mut arr, i));
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut`
error[E0282]: type annotations needed
- --> $DIR/method-chain.rs:21:33
+ --> $DIR/method-chain.rs:20:33
|
LL | Foo.bar().bar().bar().bar().baz();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
error[E0282]: type annotations needed
- --> $DIR/method-chain.rs:21:33
+ --> $DIR/method-chain.rs:20:33
|
LL | Foo.bar().bar().bar().bar().baz();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo;
error[E0282]: type annotations needed
- --> $DIR/uninferred-consts.rs:14:9
+ --> $DIR/uninferred-consts.rs:13:9
|
LL | Foo.foo();
| ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
error[E0282]: type annotations needed
- --> $DIR/uninferred-consts.rs:14:9
+ --> $DIR/uninferred-consts.rs:13:9
|
LL | Foo.foo();
| ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
struct Foo;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: usize> {
arr: [u8; N],
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn as_chunks<const N: usize>() -> [u8; N] {
loop {}
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn takes_closure_of_array_3<F>(f: F) where F: Fn([i32; 3]) {
f([1, 2, 3]);
error: constant expression depends on a generic parameter
- --> $DIR/intrinsics-type_name-as-const-argument.rs:15:8
+ --> $DIR/intrinsics-type_name-as-const-argument.rs:14:8
|
LL | T: Trait<{std::intrinsics::type_name::<T>()}>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44
+ --> $DIR/intrinsics-type_name-as-const-argument.rs:14:44
|
LL | T: Trait<{std::intrinsics::type_name::<T>()}>
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: `&'static str` is forbidden as the type of a const generic parameter
- --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
+ --> $DIR/intrinsics-type_name-as-const-argument.rs:9:22
|
LL | trait Trait<const S: &'static str> {}
| ^^^^^^^^^^^^
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
#![feature(core_intrinsics)]
#![feature(const_type_name)]
error: constant expression depends on a generic parameter
- --> $DIR/issue-61522-array-len-succ.rs:7:40
+ --> $DIR/issue-61522-array-len-succ.rs:6:40
|
LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
| ^^^^^^^^^^^^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-61522-array-len-succ.rs:12:24
+ --> $DIR/issue-61522-array-len-succ.rs:11:24
|
LL | fn inner(&self) -> &[u8; COUNT + 1] {
| ^^^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-61522-array-len-succ.rs:7:45
+ --> $DIR/issue-61522-array-len-succ.rs:6:45
|
LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
| ^^^^^ cannot perform const operation using `COUNT`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-61522-array-len-succ.rs:12:30
+ --> $DIR/issue-61522-array-len-succ.rs:11:30
|
LL | fn inner(&self) -> &[u8; COUNT + 1] {
| ^^^^^ cannot perform const operation using `COUNT`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
//[full]~^ ERROR constant expression depends on a generic parameter
error: `&'static str` is forbidden as the type of a const generic parameter
- --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:9:25
+ --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:8:25
|
LL | trait Trait<const NAME: &'static str> {
| ^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Trait<const NAME: &'static str> {
warning: cannot use constants which depend on generic parameters in types
- --> $DIR/issue-67375.rs:9:12
+ --> $DIR/issue-67375.rs:8:12
|
LL | inner: [(); { [|_: &T| {}; 0].len() }],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
error[E0392]: parameter `T` is never used
- --> $DIR/issue-67375.rs:7:12
+ --> $DIR/issue-67375.rs:6:12
|
LL | struct Bug<T> {
| ^ unused parameter
error: generic parameters may not be used in const operations
- --> $DIR/issue-67375.rs:9:25
+ --> $DIR/issue-67375.rs:8:25
|
LL | inner: [(); { [|_: &T| {}; 0].len() }],
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0392]: parameter `T` is never used
- --> $DIR/issue-67375.rs:7:12
+ --> $DIR/issue-67375.rs:6:12
|
LL | struct Bug<T> {
| ^ unused parameter
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Bug<T> {
//~^ ERROR parameter `T` is never used
error[E0308]: mismatched types
- --> $DIR/issue-67945-1.rs:14:20
+ --> $DIR/issue-67945-1.rs:13:20
|
LL | struct Bug<S> {
| - this type parameter
found union `MaybeUninit<_>`
error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-1.rs:11:12
+ --> $DIR/issue-67945-1.rs:10:12
|
LL | struct Bug<S> {
| ^ unused parameter
error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-1.rs:14:16
+ --> $DIR/issue-67945-1.rs:13:16
|
LL | let x: S = MaybeUninit::uninit();
| ^ cannot perform const operation using `S`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-1.rs:17:45
+ --> $DIR/issue-67945-1.rs:16:45
|
LL | let b = &*(&x as *const _ as *const S);
| ^ cannot perform const operation using `S`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-1.rs:11:12
+ --> $DIR/issue-67945-1.rs:10:12
|
LL | struct Bug<S> {
| ^ unused parameter
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::marker::PhantomData;
error[E0308]: mismatched types
- --> $DIR/issue-67945-2.rs:12:20
+ --> $DIR/issue-67945-2.rs:11:20
|
LL | struct Bug<S> {
| - this type parameter
found union `MaybeUninit<_>`
error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-2.rs:9:12
+ --> $DIR/issue-67945-2.rs:8:12
|
LL | struct Bug<S> {
| ^ unused parameter
error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-2.rs:12:16
+ --> $DIR/issue-67945-2.rs:11:16
|
LL | let x: S = MaybeUninit::uninit();
| ^ cannot perform const operation using `S`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-67945-2.rs:15:45
+ --> $DIR/issue-67945-2.rs:14:45
|
LL | let b = &*(&x as *const _ as *const S);
| ^ cannot perform const operation using `S`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-2.rs:9:12
+ --> $DIR/issue-67945-2.rs:8:12
|
LL | struct Bug<S> {
| ^ unused parameter
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::mem::MaybeUninit;
error: constant expression depends on a generic parameter
- --> $DIR/issue-67945-3.rs:8:8
+ --> $DIR/issue-67945-3.rs:7:8
|
LL | A: [(); {
| ________^
error: generic `Self` types are currently not permitted in anonymous constants
- --> $DIR/issue-67945-3.rs:10:27
+ --> $DIR/issue-67945-3.rs:9:27
|
LL | let x: Option<Box<Self>> = None;
| ^^^^
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Bug<S: ?Sized> {
A: [(); {
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
extern crate impl_const;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub fn works() {
let array/*: [_; _]*/ = default_array();
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn works() {
let array/*: [u8; _]*/ = default_byte_array();
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub trait Foo<const B: bool> {}
pub fn bar<T: Foo<{ true }>>() {}
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
const SIZE: usize = 16;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
// All of these three items must be in `lib2` to reproduce the error
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error[E0771]: use of non-static lifetime `'a` in const generic
- --> $DIR/issue-56445.rs:9:26
+ --> $DIR/issue-56445.rs:8:26
|
LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
| ^^
error[E0771]: use of non-static lifetime `'a` in const generic
- --> $DIR/issue-56445.rs:9:26
+ --> $DIR/issue-56445.rs:8:26
|
LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
| ^^
// Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995.
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
#![crate_type = "lib"]
use std::marker::PhantomData;
+++ /dev/null
-struct B<const I: u8>; //~ ERROR const generics are unstable
-
-impl B<0> {
- fn bug() -> Self {
- panic!()
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: const generics are unstable
- --> $DIR/issue-60263.rs:1:16
- |
-LL | struct B<const I: u8>;
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: 1 warning emitted
// check-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
struct Generic<const V: usize>;
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: 1 warning emitted
// build-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; N]
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-61336-2.rs:10:5
+ --> $DIR/issue-61336-2.rs:9:5
|
LL | [x; { N }]
| ^^^^^^^^^^ the trait `Copy` is not implemented for `T`
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-61336-2.rs:10:5
+ --> $DIR/issue-61336-2.rs:9:5
|
LL | [x; { N }]
| ^^^^^^^^^^ the trait `Copy` is not implemented for `T`
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; { N }]
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-61336.rs:10:5
+ --> $DIR/issue-61336.rs:9:5
|
LL | [x; N]
| ^^^^^^ the trait `Copy` is not implemented for `T`
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-61336.rs:10:5
+ --> $DIR/issue-61336.rs:9:5
|
LL | [x; N]
| ^^^^^^ the trait `Copy` is not implemented for `T`
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; N]
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: 1 warning emitted
// check-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
use std::mem;
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: 1 warning emitted
// run-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
fn promote<const N: i32>() {
// works:
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: constant expression depends on a generic parameter
- --> $DIR/issue-61747.rs:8:23
+ --> $DIR/issue-61747.rs:7:23
|
LL | fn successor() -> Const<{C + 1}> {
| ^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-61747.rs:8:30
+ --> $DIR/issue-61747.rs:7:30
|
LL | fn successor() -> Const<{C + 1}> {
| ^ cannot perform const operation using `C`
// revisions: full min
#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
-#![cfg_attr(min, feature(min_const_generics))]
struct Const<const N: usize>;
error: constant expression depends on a generic parameter
- --> $DIR/issue-61935.rs:10:14
+ --> $DIR/issue-61935.rs:9:14
|
LL | Self:FooImpl<{N==0}>
| ^^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-61935.rs:10:23
+ --> $DIR/issue-61935.rs:9:23
|
LL | Self:FooImpl<{N==0}>
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Foo {}
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub trait BitLen: Sized {
const BIT_LEN: usize;
error: constant expression depends on a generic parameter
- --> $DIR/issue-62220.rs:13:27
+ --> $DIR/issue-62220.rs:12:27
|
LL | pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-62220.rs:8:59
+ --> $DIR/issue-62220.rs:7:59
|
LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct Vector<T, const N: usize>([T; N]);
error: constant expression depends on a generic parameter
- --> $DIR/issue-62456.rs:7:20
+ --> $DIR/issue-62456.rs:6:20
|
LL | let _ = [0u64; N + 1];
| ^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-62456.rs:7:20
+ --> $DIR/issue-62456.rs:6:20
|
LL | let _ = [0u64; N + 1];
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const N: usize>() {
let _ = [0u64; N + 1];
error: constant expression depends on a generic parameter
- --> $DIR/issue-62504.rs:19:25
+ --> $DIR/issue-62504.rs:18:25
|
LL | ArrayHolder([0; Self::SIZE])
| ^^^^^^^^^^
error[E0308]: mismatched types
- --> $DIR/issue-62504.rs:19:21
+ --> $DIR/issue-62504.rs:18:21
|
LL | ArrayHolder([0; Self::SIZE])
| ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
found array `[u32; _]`
error: constant expression depends on a generic parameter
- --> $DIR/issue-62504.rs:19:25
+ --> $DIR/issue-62504.rs:18:25
|
LL | ArrayHolder([0; Self::SIZE])
| ^^^^^^^^^^
#![allow(incomplete_features)]
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait HasSize {
const SIZE: usize;
error: `NoMatch` is forbidden as the type of a const generic parameter
- --> $DIR/issue-62579-no-match.rs:10:17
+ --> $DIR/issue-62579-no-match.rs:9:17
|
LL | fn foo<const T: NoMatch>() -> bool {
| ^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[derive(PartialEq, Eq)]
struct NoMatch;
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-62878.rs:6:38
+ --> $DIR/issue-62878.rs:5:38
|
LL | fn foo<const N: usize, const A: [u8; N]>() {}
| ^ the type must not depend on the parameter `N`
error[E0747]: type provided when a constant was expected
- --> $DIR/issue-62878.rs:11:11
+ --> $DIR/issue-62878.rs:10:11
|
LL | foo::<_, {[1]}>();
| ^
= help: const arguments cannot yet be inferred with `_`
error[E0308]: mismatched types
- --> $DIR/issue-62878.rs:11:15
+ --> $DIR/issue-62878.rs:10:15
|
LL | foo::<_, {[1]}>();
| ^^^ expected `usize`, found array `[{integer}; 1]`
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-62878.rs:6:38
+ --> $DIR/issue-62878.rs:5:38
|
LL | fn foo<const N: usize, const A: [u8; N]>() {}
| ^ the type must not depend on the parameter `N`
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-62878.rs:6:33
+ --> $DIR/issue-62878.rs:5:33
|
LL | fn foo<const N: usize, const A: [u8; N]>() {}
| ^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const N: usize, const A: [u8; N]>() {}
//~^ ERROR the type of const parameters must not
error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
- --> $DIR/issue-63322-forbid-dyn.rs:10:18
+ --> $DIR/issue-63322-forbid-dyn.rs:9:18
|
LL | fn test<const T: &'static dyn A>() {
| ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq`
error: `&'static (dyn A + 'static)` is forbidden as the type of a const generic parameter
- --> $DIR/issue-63322-forbid-dyn.rs:10:18
+ --> $DIR/issue-63322-forbid-dyn.rs:9:18
|
LL | fn test<const T: &'static dyn A>() {
| ^^^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
- --> $DIR/issue-63322-forbid-dyn.rs:10:18
+ --> $DIR/issue-63322-forbid-dyn.rs:9:18
|
LL | fn test<const T: &'static dyn A>() {
| ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait A {}
struct B;
error: constant expression depends on a generic parameter
- --> $DIR/issue-64494.rs:16:53
+ --> $DIR/issue-64494.rs:15:53
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
| ^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-64494.rs:19:53
+ --> $DIR/issue-64494.rs:18:53
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
| ^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-64494.rs:16:38
+ --> $DIR/issue-64494.rs:15:38
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
| ^^^^^^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-64494.rs:19:38
+ --> $DIR/issue-64494.rs:18:38
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
| ^^^^^^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0119]: conflicting implementations of trait `MyTrait`:
- --> $DIR/issue-64494.rs:19:1
+ --> $DIR/issue-64494.rs:18:1
|
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
| ------------------------------------ first implementation here
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Foo {
const VAL: usize;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo<const D: usize> {
state: Option<[u8; D]>,
error: constant expression depends on a generic parameter
- --> $DIR/issue-66205.rs:8:12
+ --> $DIR/issue-66205.rs:7:12
|
LL | fact::<{ N - 1 }>();
| ^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-66205.rs:8:14
+ --> $DIR/issue-66205.rs:7:14
|
LL | fact::<{ N - 1 }>();
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![allow(dead_code, unconditional_recursion)]
fn fact<const N: usize>() {
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct Tuple;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Baz {
type Quaks;
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:17:1
+ --> $DIR/issue-67185-2.rs:16:1
|
LL | / trait Foo
LL | |
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:17:1
+ --> $DIR/issue-67185-2.rs:16:1
|
LL | / trait Foo
LL | |
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:27:6
+ --> $DIR/issue-67185-2.rs:26:6
|
LL | trait Foo
| --- required by a bound in this
<[u16; 4] as Bar>
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:27:6
+ --> $DIR/issue-67185-2.rs:26:6
|
LL | trait Foo
| --- required by a bound in this
<[u16; 4] as Bar>
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:31:14
+ --> $DIR/issue-67185-2.rs:30:14
|
LL | trait Foo
| --- required by a bound in this
<[u16; 4] as Bar>
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:31:14
+ --> $DIR/issue-67185-2.rs:30:14
|
LL | trait Foo
| --- required by a bound in this
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:17:1
+ --> $DIR/issue-67185-2.rs:16:1
|
LL | / trait Foo
LL | |
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:17:1
+ --> $DIR/issue-67185-2.rs:16:1
|
LL | / trait Foo
LL | |
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:27:6
+ --> $DIR/issue-67185-2.rs:26:6
|
LL | trait Foo
| --- required by a bound in this
<[u16; 4] as Bar>
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:27:6
+ --> $DIR/issue-67185-2.rs:26:6
|
LL | trait Foo
| --- required by a bound in this
<[u16; 4] as Bar>
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:31:14
+ --> $DIR/issue-67185-2.rs:30:14
|
LL | trait Foo
| --- required by a bound in this
<[u16; 4] as Bar>
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
- --> $DIR/issue-67185-2.rs:31:14
+ --> $DIR/issue-67185-2.rs:30:14
|
LL | trait Foo
| --- required by a bound in this
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Baz {
type Quaks;
error: constant expression depends on a generic parameter
- --> $DIR/issue-67739.rs:12:15
+ --> $DIR/issue-67739.rs:11:15
|
LL | [0u8; mem::size_of::<Self::Associated>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: constant expression depends on a generic parameter
- --> $DIR/issue-67739.rs:12:15
+ --> $DIR/issue-67739.rs:11:15
|
LL | [0u8; mem::size_of::<Self::Associated>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::mem;
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-68366.rs:12:13
+ --> $DIR/issue-68366.rs:11:13
|
LL | impl <const N: usize> Collatz<{Some(N)}> {}
| ^ unconstrained const parameter
= note: proving the result of expressions other than the parameter are unique is not supported
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-68366.rs:18:12
+ --> $DIR/issue-68366.rs:17:12
|
LL | impl<const N: usize> Foo {}
| ^ unconstrained const parameter
error: generic parameters may not be used in const operations
- --> $DIR/issue-68366.rs:12:37
+ --> $DIR/issue-68366.rs:11:37
|
LL | impl <const N: usize> Collatz<{Some(N)}> {}
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-68366.rs:12:13
+ --> $DIR/issue-68366.rs:11:13
|
LL | impl <const N: usize> Collatz<{Some(N)}> {}
| ^ unconstrained const parameter
= note: proving the result of expressions other than the parameter are unique is not supported
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-68366.rs:18:12
+ --> $DIR/issue-68366.rs:17:12
|
LL | impl<const N: usize> Foo {}
| ^ unconstrained const parameter
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Collatz<const N: Option<usize>>;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct S(u8);
error: `[usize; 0]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-68615-adt.rs:7:23
+ --> $DIR/issue-68615-adt.rs:6:23
|
LL | struct Const<const V: [usize; 0]> {}
| ^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Const<const V: [usize; 0]> {}
//[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter
error: `[usize; 0]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-68615-array.rs:7:21
+ --> $DIR/issue-68615-array.rs:6:21
|
LL | struct Foo<const V: [usize; 0] > {}
| ^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo<const V: [usize; 0] > {}
//[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter
error: constant expression depends on a generic parameter
- --> $DIR/issue-68977.rs:35:44
+ --> $DIR/issue-68977.rs:34:44
|
LL | FxpStorageHelper<INT_BITS, FRAC_BITS>: FxpStorage,
| ^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-68977.rs:29:17
+ --> $DIR/issue-68977.rs:28:17
|
LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
| ^^^^^^^^ cannot perform const operation using `INT_BITS`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-68977.rs:29:28
+ --> $DIR/issue-68977.rs:28:28
|
LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
| ^^^^^^^^^ cannot perform const operation using `FRAC_BITS`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct PhantomU8<const X: u8>;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
const L: usize = 4;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn main() {
<()>::foo();
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub trait Trait<const N: usize>: From<<Self as Trait<N>>::Item> {
type Item;
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71169.rs:6:43
+ --> $DIR/issue-71169.rs:5:43
|
LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
| ^^^ the type must not depend on the parameter `LEN`
error: constant expression depends on a generic parameter
- --> $DIR/issue-71169.rs:11:14
+ --> $DIR/issue-71169.rs:10:14
|
LL | foo::<4, DATA>();
| ^^^^
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71169.rs:6:43
+ --> $DIR/issue-71169.rs:5:43
|
LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
| ^^^ the type must not depend on the parameter `LEN`
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-71169.rs:6:38
+ --> $DIR/issue-71169.rs:5:38
|
LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
| ^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
//~^ ERROR the type of const parameters must not
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71381.rs:15:82
+ --> $DIR/issue-71381.rs:14:82
|
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
| ^^^^ the type must not depend on the parameter `Args`
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71381.rs:24:40
+ --> $DIR/issue-71381.rs:23:40
|
LL | const FN: unsafe extern "C" fn(Args),
| ^^^^ the type must not depend on the parameter `Args`
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71381.rs:15:61
+ --> $DIR/issue-71381.rs:14:61
|
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71381.rs:24:19
+ --> $DIR/issue-71381.rs:23:19
|
LL | const FN: unsafe extern "C" fn(Args),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71381.rs:15:82
+ --> $DIR/issue-71381.rs:14:82
|
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
| ^^^^ the type must not depend on the parameter `Args`
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71381.rs:24:40
+ --> $DIR/issue-71381.rs:23:40
|
LL | const FN: unsafe extern "C" fn(Args),
| ^^^^ the type must not depend on the parameter `Args`
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71381.rs:15:61
+ --> $DIR/issue-71381.rs:14:61
|
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71381.rs:24:19
+ --> $DIR/issue-71381.rs:23:19
|
LL | const FN: unsafe extern "C" fn(Args),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Test(*const usize);
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71382.rs:17:23
+ --> $DIR/issue-71382.rs:16:23
|
LL | fn test<const FN: fn()>(&self) {
| ^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71382.rs:17:23
+ --> $DIR/issue-71382.rs:16:23
|
LL | fn test<const FN: fn()>(&self) {
| ^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Test();
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71611.rs:6:31
+ --> $DIR/issue-71611.rs:5:31
|
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
| ^ the type must not depend on the parameter `A`
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71611.rs:6:21
+ --> $DIR/issue-71611.rs:5:21
|
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
| ^^^^^^^^^^^^
error[E0770]: the type of const parameters must not depend on other generic parameters
- --> $DIR/issue-71611.rs:6:31
+ --> $DIR/issue-71611.rs:5:31
|
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
| ^ the type must not depend on the parameter `A`
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71611.rs:6:21
+ --> $DIR/issue-71611.rs:5:21
|
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
| ^^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn func<A, const F: fn(inner: A)>(outer: A) {
//~^ ERROR: using function pointers as const generic parameters is forbidden
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-72352.rs:8:42
+ --> $DIR/issue-72352.rs:7:42
|
LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
| ^^^^^^^^^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-72352.rs:8:42
+ --> $DIR/issue-72352.rs:7:42
|
LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
| ^^^^^^^^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::ffi::{CStr, CString};
error: constant expression depends on a generic parameter
- --> $DIR/issue-72787.rs:11:32
+ --> $DIR/issue-72787.rs:10:32
|
LL | Condition<{ LHS <= RHS }>: True
| ^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-72787.rs:26:42
+ --> $DIR/issue-72787.rs:25:42
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-72787.rs:26:42
+ --> $DIR/issue-72787.rs:25:42
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-72787.rs:26:42
+ --> $DIR/issue-72787.rs:25:42
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-72787.rs:26:42
+ --> $DIR/issue-72787.rs:25:42
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:11:17
+ --> $DIR/issue-72787.rs:10:17
|
LL | Condition<{ LHS <= RHS }>: True
| ^^^ cannot perform const operation using `LHS`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:11:24
+ --> $DIR/issue-72787.rs:10:24
|
LL | Condition<{ LHS <= RHS }>: True
| ^^^ cannot perform const operation using `RHS`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:26:25
+ --> $DIR/issue-72787.rs:25:25
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^ cannot perform const operation using `I`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:26:36
+ --> $DIR/issue-72787.rs:25:36
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^ cannot perform const operation using `J`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0283]: type annotations needed
- --> $DIR/issue-72787.rs:22:26
+ --> $DIR/issue-72787.rs:21:26
|
LL | pub trait True {}
| -------------- required by this bound in `True`
= note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
error[E0283]: type annotations needed
- --> $DIR/issue-72787.rs:22:26
+ --> $DIR/issue-72787.rs:21:26
|
LL | pub trait True {}
| -------------- required by this bound in `True`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct IsLessOrEqual<const LHS: u32, const RHS: u32>;
pub struct Condition<const CONDITION: bool>;
error: constant expression depends on a generic parameter
- --> $DIR/issue-72819-generic-in-const-eval.rs:9:39
+ --> $DIR/issue-72819-generic-in-const-eval.rs:8:39
|
LL | where Assert::<{N < usize::MAX / 2}>: IsTrue,
| ^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-72819-generic-in-const-eval.rs:9:17
+ --> $DIR/issue-72819-generic-in-const-eval.rs:8:17
|
LL | where Assert::<{N < usize::MAX / 2}>: IsTrue,
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Arr<const N: usize>
where Assert::<{N < usize::MAX / 2}>: IsTrue,
error: `[u32; _]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-73491.rs:9:19
+ --> $DIR/issue-73491.rs:8:19
|
LL | fn hoge<const IN: [u32; LEN]>() {}
| ^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
const LEN: usize = 1024;
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/issue-73508.rs:6:33
+ --> $DIR/issue-73508.rs:5:33
|
LL | pub const fn func_name<const X: *const u32>() {}
| ^^^^^^^^^^
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/issue-73508.rs:6:33
+ --> $DIR/issue-73508.rs:5:33
|
LL | pub const fn func_name<const X: *const u32>() {}
| ^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub const fn func_name<const X: *const u32>() {}
//~^ ERROR using raw pointers
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74101.rs:7:18
+ --> $DIR/issue-74101.rs:6:18
|
LL | fn test<const N: [u8; 1 + 2]>() {}
| ^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74101.rs:10:21
+ --> $DIR/issue-74101.rs:9:21
|
LL | struct Foo<const N: [u8; 1 + 2]>;
| ^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn test<const N: [u8; 1 + 2]>() {}
//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter
error: `IceEnum` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74255.rs:15:31
+ --> $DIR/issue-74255.rs:14:31
|
LL | fn ice_struct_fn<const I: IceEnum>() {}
| ^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[derive(PartialEq, Eq)]
enum IceEnum {
error: `Inner` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74950.rs:18:23
+ --> $DIR/issue-74950.rs:17:23
|
LL | struct Outer<const I: Inner>;
| ^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `Inner` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74950.rs:18:23
+ --> $DIR/issue-74950.rs:17:23
|
LL | struct Outer<const I: Inner>;
| ^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `Inner` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74950.rs:18:23
+ --> $DIR/issue-74950.rs:17:23
|
LL | struct Outer<const I: Inner>;
| ^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `Inner` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74950.rs:18:23
+ --> $DIR/issue-74950.rs:17:23
|
LL | struct Outer<const I: Inner>;
| ^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `Inner` is forbidden as the type of a const generic parameter
- --> $DIR/issue-74950.rs:18:23
+ --> $DIR/issue-74950.rs:17:23
|
LL | struct Outer<const I: Inner>;
| ^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[derive(PartialEq, Eq)]
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/issue-75047.rs:15:21
+ --> $DIR/issue-75047.rs:14:21
|
LL | struct Foo<const N: [u8; Bar::<u32>::value()]>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Bar<T>(T);
error: constant expression depends on a generic parameter
- --> $DIR/issue-76701-ty-param-in-const.rs:6:21
+ --> $DIR/issue-76701-ty-param-in-const.rs:5:21
|
LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/issue-76701-ty-param-in-const.rs:12:37
+ --> $DIR/issue-76701-ty-param-in-const.rs:11:37
|
LL | fn const_param<const N: usize>() -> [u8; N + 1] {
| ^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/issue-76701-ty-param-in-const.rs:6:46
+ --> $DIR/issue-76701-ty-param-in-const.rs:5:46
|
LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-76701-ty-param-in-const.rs:12:42
+ --> $DIR/issue-76701-ty-param-in-const.rs:11:42
|
LL | fn const_param<const N: usize>() -> [u8; N + 1] {
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
//[full]~^ ERROR constant expression depends on a generic parameter
--- /dev/null
+// Regression test for issue #80062 (fixed by `min_const_generics`)
+
+fn sof<T>() -> T { unimplemented!() }
+
+fn test<T>() {
+ let _: [u8; sof::<T>()];
+ //~^ ERROR generic parameters may not be used in const operations
+}
+
+fn main() {}
--- /dev/null
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-80062.rs:6:23
+ |
+LL | let _: [u8; sof::<T>()];
+ | ^ cannot perform const operation using `T`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: aborting due to previous error
+
--- /dev/null
+struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+//~^ ERROR generic parameters may not be used in const operations
+
+fn main() {}
--- /dev/null
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-80375.rs:1:41
+ |
+LL | struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
+ | ^^^^^ cannot perform const operation using `COUNT`
+ |
+ = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: aborting due to previous error
+
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait T<const A: usize> {
fn f();
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:49:17
+ --> $DIR/macro_rules-braces.rs:48:17
|
LL | let _: baz!(m::P);
| ^^^^
| ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:69:17
+ --> $DIR/macro_rules-braces.rs:68:17
|
LL | let _: baz!(10 + 7);
| ^^^^^^
| ^ ^
error: constant expression depends on a generic parameter
- --> $DIR/macro_rules-braces.rs:16:13
+ --> $DIR/macro_rules-braces.rs:15:13
|
LL | [u8; $x]
| ^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: constant expression depends on a generic parameter
- --> $DIR/macro_rules-braces.rs:21:13
+ --> $DIR/macro_rules-braces.rs:20:13
|
LL | [u8; { $x }]
| ^^^^^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: constant expression depends on a generic parameter
- --> $DIR/macro_rules-braces.rs:26:13
+ --> $DIR/macro_rules-braces.rs:25:13
|
LL | Foo<$x>
| ^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: constant expression depends on a generic parameter
- --> $DIR/macro_rules-braces.rs:31:13
+ --> $DIR/macro_rules-braces.rs:30:13
|
LL | Foo<{ $x }>
| ^^^^^^^^^^^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:49:17
+ --> $DIR/macro_rules-braces.rs:48:17
|
LL | let _: baz!(m::P);
| ^^^^
| ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:69:17
+ --> $DIR/macro_rules-braces.rs:68:17
|
LL | let _: baz!(10 + 7);
| ^^^^^^
| ^ ^
error: generic parameters may not be used in const operations
- --> $DIR/macro_rules-braces.rs:37:20
+ --> $DIR/macro_rules-braces.rs:36:20
|
LL | let _: foo!({{ N }});
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/macro_rules-braces.rs:41:19
+ --> $DIR/macro_rules-braces.rs:40:19
|
LL | let _: bar!({ N });
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/macro_rules-braces.rs:46:20
+ --> $DIR/macro_rules-braces.rs:45:20
|
LL | let _: baz!({{ N }});
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/macro_rules-braces.rs:51:19
+ --> $DIR/macro_rules-braces.rs:50:19
|
LL | let _: biz!({ N });
| ^ cannot perform const operation using `N`
// revisions: full min
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
mod m {
pub const P: usize = 0;
+++ /dev/null
-#![feature(const_generics)]
-//~^ ERROR features `const_generics` and `min_const_generics` are incompatible
-#![allow(incomplete_features)]
-#![feature(min_const_generics)]
-
-
-fn main() {}
+++ /dev/null
-error: features `const_generics` and `min_const_generics` are incompatible, using them at the same time is not allowed
- --> $DIR/min-and-full-same-time.rs:1:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
-...
-LL | #![feature(min_const_generics)]
- | ^^^^^^^^^^^^^^^^^^
- |
- = help: remove one of these features
-
-error: aborting due to previous error
-
// check-pass
-#![feature(min_const_generics)]
-
struct Foo<const N: usize>;
impl<const N: usize> Foo<N> {
-#![feature(min_const_generics)]
-
use std::mem::size_of;
fn test<const N: usize>() {}
error: generic parameters may not be used in const operations
- --> $DIR/complex-expression.rs:11:38
+ --> $DIR/complex-expression.rs:9:38
|
LL | struct Break0<const N: usize>([u8; { N + 1 }]);
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/complex-expression.rs:14:40
+ --> $DIR/complex-expression.rs:12:40
|
LL | struct Break1<const N: usize>([u8; { { N } }]);
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/complex-expression.rs:18:17
+ --> $DIR/complex-expression.rs:16:17
|
LL | let _: [u8; N + 1];
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/complex-expression.rs:23:17
+ --> $DIR/complex-expression.rs:21:17
|
LL | let _ = [0; N + 1];
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/complex-expression.rs:27:45
+ --> $DIR/complex-expression.rs:25:45
|
LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/complex-expression.rs:30:47
+ --> $DIR/complex-expression.rs:28:47
|
LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/complex-expression.rs:34:32
+ --> $DIR/complex-expression.rs:32:32
|
LL | let _: [u8; size_of::<*mut T>() + 1];
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
warning: cannot use constants which depend on generic parameters in types
- --> $DIR/complex-expression.rs:39:17
+ --> $DIR/complex-expression.rs:37:17
|
LL | let _ = [0; size_of::<*mut T>() + 1];
| ^^^^^^^^^^^^^^^^^^^^^^^
-#![feature(min_const_generics)]
#![feature(never_type)]
struct Foo<const N: [u8; 0]>;
error: `[u8; 0]` is forbidden as the type of a const generic parameter
- --> $DIR/complex-types.rs:4:21
+ --> $DIR/complex-types.rs:3:21
|
LL | struct Foo<const N: [u8; 0]>;
| ^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `()` is forbidden as the type of a const generic parameter
- --> $DIR/complex-types.rs:7:21
+ --> $DIR/complex-types.rs:6:21
|
LL | struct Bar<const N: ()>;
| ^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `No` is forbidden as the type of a const generic parameter
- --> $DIR/complex-types.rs:12:21
+ --> $DIR/complex-types.rs:11:21
|
LL | struct Fez<const N: No>;
| ^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
- --> $DIR/complex-types.rs:15:21
+ --> $DIR/complex-types.rs:14:21
|
LL | struct Faz<const N: &'static u8>;
| ^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `!` is forbidden as the type of a const generic parameter
- --> $DIR/complex-types.rs:18:21
+ --> $DIR/complex-types.rs:17:21
|
LL | struct Fiz<const N: !>;
| ^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `()` is forbidden as the type of a const generic parameter
- --> $DIR/complex-types.rs:21:19
+ --> $DIR/complex-types.rs:20:19
|
LL | enum Goo<const N: ()> { A, B }
| ^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `()` is forbidden as the type of a const generic parameter
- --> $DIR/complex-types.rs:24:20
+ --> $DIR/complex-types.rs:23:20
|
LL | union Boo<const N: ()> { a: () }
| ^^
// check-pass
-#![feature(min_const_generics)]
#![allow(dead_code)]
fn foo<T>() {
warning: cannot use constants which depend on generic parameters in types
- --> $DIR/const-evaluatable-unchecked.rs:6:9
+ --> $DIR/const-evaluatable-unchecked.rs:5:9
|
LL | [0; std::mem::size_of::<*mut T>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
warning: cannot use constants which depend on generic parameters in types
- --> $DIR/const-evaluatable-unchecked.rs:17:21
+ --> $DIR/const-evaluatable-unchecked.rs:16:21
|
LL | let _ = [0; Self::ASSOC];
| ^^^^^^^^^^^
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
warning: cannot use constants which depend on generic parameters in types
- --> $DIR/const-evaluatable-unchecked.rs:29:21
+ --> $DIR/const-evaluatable-unchecked.rs:28:21
|
LL | let _ = [0; Self::ASSOC];
| ^^^^^^^^^^^
-#![feature(min_const_generics)]
-
fn foo<const C: usize>() {}
const BAR: usize = 42;
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:8:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:6:8
|
LL | foo<BAR + 3>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:11:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:9:8
|
LL | foo<BAR + BAR>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:14:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:12:8
|
LL | foo<3 + 3>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:17:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:15:8
|
LL | foo<BAR - 3>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:20:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:18:8
|
LL | foo<BAR - BAR>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:23:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:21:8
|
LL | foo<100 - BAR>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:24:8
|
LL | foo<bar<i32>()>();
| ^ ^
| ^^
error: expected one of `;` or `}`, found `>`
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:19
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:24:19
|
LL | foo<bar<i32>()>();
| ^ expected one of `;` or `}`
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:30:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:28:8
|
LL | foo<bar::<i32>()>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:33:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:31:8
|
LL | foo<bar::<i32>() + BAR>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:36:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:34:8
|
LL | foo<bar::<i32>() - BAR>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:39:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:37:8
|
LL | foo<BAR - bar::<i32>()>();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:42:8
+ --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:40:8
|
LL | foo<BAR - bar::<i32>()>();
| ^ ^
-#![feature(min_const_generics)]
-
fn foo<const C: usize>() {}
const BAR: usize = 42;
error: expected one of `,` or `>`, found `3`
- --> $DIR/const-expression-suggest-missing-braces.rs:8:17
+ --> $DIR/const-expression-suggest-missing-braces.rs:6:17
|
LL | foo::<BAR + 3>();
| ^ expected one of `,` or `>`
| ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:20:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:18:11
|
LL | foo::<3 + 3>();
| ^^^^^
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:23:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:21:15
|
LL | foo::<BAR - 3>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:26:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:24:15
|
LL | foo::<BAR - BAR>();
| ^ expected one of `,` or `>`
| ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:29:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:27:11
|
LL | foo::<100 - BAR>();
| ^^^^^^^^^
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:32:19
+ --> $DIR/const-expression-suggest-missing-braces.rs:30:19
|
LL | foo::<bar<i32>()>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:35:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:33:21
|
LL | foo::<bar::<i32>()>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:38:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:36:21
|
LL | foo::<bar::<i32>() + BAR>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:41:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:39:21
|
LL | foo::<bar::<i32>() - BAR>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:44:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:42:15
|
LL | foo::<BAR - bar::<i32>()>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:47:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:45:15
|
LL | foo::<BAR - bar::<i32>()>();
| ^ expected one of `,` or `>`
| ^ ^
error[E0404]: expected trait, found constant `BAR`
- --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:11:11
|
LL | foo::<BAR + BAR>();
| ^^^ not a trait
error[E0404]: expected trait, found constant `BAR`
- --> $DIR/const-expression-suggest-missing-braces.rs:13:17
+ --> $DIR/const-expression-suggest-missing-braces.rs:11:17
|
LL | foo::<BAR + BAR>();
| ^^^ not a trait
warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:11:11
|
LL | foo::<BAR + BAR>();
| ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
= note: `#[warn(bare_trait_objects)]` on by default
error[E0747]: type provided when a constant was expected
- --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:11:11
|
LL | foo::<BAR + BAR>();
| ^^^^^^^^^
// run-pass
-#![feature(min_const_generics)]
-
const fn identity<const T: u32>() -> u32 { T }
#[derive(Eq, PartialEq, Debug)]
-#![feature(min_const_generics)]
-
fn foo<const SIZE: usize = 5>() {}
//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
- --> $DIR/default_function_param.rs:3:26
+ --> $DIR/default_function_param.rs:1:26
|
LL | fn foo<const SIZE: usize = 5>() {}
| ^ expected one of 7 possible tokens
-#![feature(min_const_generics)]
-
trait Foo<const KIND: bool = true> {}
//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
- --> $DIR/default_trait_param.rs:3:28
+ --> $DIR/default_trait_param.rs:1:28
|
LL | trait Foo<const KIND: bool = true> {}
| ^ expected one of 7 possible tokens
+++ /dev/null
-fn test<const N: usize>() {}
-//~^ ERROR const generics are unstable
-
-fn main() {}
+++ /dev/null
-error[E0658]: const generics are unstable
- --> $DIR/feature-gate-min_const_generics.rs:1:15
- |
-LL | fn test<const N: usize>() {}
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
-#![feature(min_const_generics)]
-
// This test checks that non-static lifetimes are prohibited under `min_const_generics`. It
// currently emits an error with `min_const_generics`. This will ICE under `const_generics`.
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/forbid-non-static-lifetimes.rs:9:22
+ --> $DIR/forbid-non-static-lifetimes.rs:7:22
|
LL | test::<{ let _: &'a (); 3 },>();
| ^^
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: a non-static lifetime is not allowed in a `const`
- --> $DIR/forbid-non-static-lifetimes.rs:23:16
+ --> $DIR/forbid-non-static-lifetimes.rs:21:16
|
LL | [(); (|_: &'a u8| (), 0).1];
| ^^
-#![feature(min_const_generics)]
use std::mem::transmute;
fn get_flag<const FlagSet: bool, const ShortName: char>() -> Option<char> {
error[E0308]: mismatched types
- --> $DIR/invalid-patterns.rs:29:21
+ --> $DIR/invalid-patterns.rs:28:21
|
LL | get_flag::<false, 0xFF>();
| ^^^^ expected `char`, found `u8`
error[E0308]: mismatched types
- --> $DIR/invalid-patterns.rs:31:14
+ --> $DIR/invalid-patterns.rs:30:14
|
LL | get_flag::<7, 'c'>();
| ^ expected `bool`, found integer
error[E0308]: mismatched types
- --> $DIR/invalid-patterns.rs:33:14
+ --> $DIR/invalid-patterns.rs:32:14
|
LL | get_flag::<42, 0x5ad>();
| ^^ expected `bool`, found integer
error[E0308]: mismatched types
- --> $DIR/invalid-patterns.rs:33:18
+ --> $DIR/invalid-patterns.rs:32:18
|
LL | get_flag::<42, 0x5ad>();
| ^^^^^ expected `char`, found `u8`
error[E0080]: it is undefined behavior to use this value
- --> $DIR/invalid-patterns.rs:38:21
+ --> $DIR/invalid-patterns.rs:37:21
|
LL | get_flag::<false, { unsafe { char_raw.character } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error[E0080]: it is undefined behavior to use this value
- --> $DIR/invalid-patterns.rs:40:14
+ --> $DIR/invalid-patterns.rs:39:14
|
LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error[E0080]: it is undefined behavior to use this value
- --> $DIR/invalid-patterns.rs:42:14
+ --> $DIR/invalid-patterns.rs:41:14
|
LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error[E0080]: it is undefined behavior to use this value
- --> $DIR/invalid-patterns.rs:42:47
+ --> $DIR/invalid-patterns.rs:41:47
|
LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
-#![feature(min_const_generics)]
-
struct Example<const N: usize>;
macro_rules! external_macro {
error: expected type, found `{`
- --> $DIR/macro-fail.rs:31:27
+ --> $DIR/macro-fail.rs:29:27
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ----------------------
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected type, found `{`
- --> $DIR/macro-fail.rs:31:27
+ --> $DIR/macro-fail.rs:29:27
|
LL | Example::<gimme_a_const!(marker)>
| ----------------------
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected type, found `{`
- --> $DIR/macro-fail.rs:6:10
+ --> $DIR/macro-fail.rs:4:10
|
LL | () => {{
| __________^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected end of macro invocation
- --> $DIR/macro-fail.rs:41:25
+ --> $DIR/macro-fail.rs:39:25
|
LL | macro_rules! gimme_a_const {
| -------------------------- when calling this macro
| ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:16:33
+ --> $DIR/macro-fail.rs:14:33
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:18:13
+ --> $DIR/macro-fail.rs:16:13
|
LL | Example::<gimme_a_const!(marker)>
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:38:25
+ --> $DIR/macro-fail.rs:36:25
|
LL | let _fail = Example::<external_macro!()>;
| ^^^^^^^^^^^^^^^^^
error[E0747]: type provided when a constant was expected
- --> $DIR/macro-fail.rs:41:25
+ --> $DIR/macro-fail.rs:39:25
|
LL | let _fail = Example::<gimme_a_const!()>;
| ^^^^^^^^^^^^^^^^
// run-pass
-#![feature(min_const_generics)]
-
struct Example<const N: usize>;
macro_rules! external_macro {
-#![feature(min_const_generics)]
-
trait Foo {
fn t1() -> [u8; std::mem::size_of::<Self>()]; //~ERROR generic parameters
}
error: generic parameters may not be used in const operations
- --> $DIR/self-ty-in-const-1.rs:4:41
+ --> $DIR/self-ty-in-const-1.rs:2:41
|
LL | fn t1() -> [u8; std::mem::size_of::<Self>()];
| ^^^^ cannot perform const operation using `Self`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic `Self` types are currently not permitted in anonymous constants
- --> $DIR/self-ty-in-const-1.rs:14:41
+ --> $DIR/self-ty-in-const-1.rs:12:41
|
LL | fn t3() -> [u8; std::mem::size_of::<Self>()] {}
| ^^^^
|
note: not a concrete type
- --> $DIR/self-ty-in-const-1.rs:13:9
+ --> $DIR/self-ty-in-const-1.rs:11:9
|
LL | impl<T> Bar<T> {
| ^^^^^^
-#![feature(min_const_generics)]
-
struct Bar<T>(T);
trait Baz {
error: generic `Self` types are currently not permitted in anonymous constants
- --> $DIR/self-ty-in-const-2.rs:17:41
+ --> $DIR/self-ty-in-const-2.rs:15:41
|
LL | let _: [u8; std::mem::size_of::<Self>()];
| ^^^^
|
note: not a concrete type
- --> $DIR/self-ty-in-const-2.rs:15:17
+ --> $DIR/self-ty-in-const-2.rs:13:17
|
LL | impl<T> Baz for Bar<T> {
| ^^^^^^
-#![feature(min_const_generics)]
-
fn a<const X: &'static [u32]>() {}
//~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter
error: `&'static [u32]` is forbidden as the type of a const generic parameter
- --> $DIR/static-reference-array-const-param.rs:3:15
+ --> $DIR/static-reference-array-const-param.rs:1:15
|
LL | fn a<const X: &'static [u32]>() {}
| ^^^^^^^^^^^^^^
-#![feature(min_const_generics)]
-
struct Const<const P: &'static ()>;
//~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
error: `&'static ()` is forbidden as the type of a const generic parameter
- --> $DIR/transmute-const-param-static-reference.rs:3:23
+ --> $DIR/transmute-const-param-static-reference.rs:1:23
|
LL | struct Const<const P: &'static ()>;
| ^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::ops::AddAssign;
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
- --> $DIR/nested-type.rs:16:5
+ --> $DIR/nested-type.rs:15:5
|
LL | Foo::<17>::value()
| ^^^^^^^^^^^^^^^^^^
error: `[u8; _]` is forbidden as the type of a const generic parameter
- --> $DIR/nested-type.rs:7:21
+ --> $DIR/nested-type.rs:6:21
|
LL | struct Foo<const N: [u8; {
| _____________________^
= help: more complex types are supported with `#[feature(const_generics)]`
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
- --> $DIR/nested-type.rs:16:5
+ --> $DIR/nested-type.rs:15:5
|
LL | Foo::<17>::value()
| ^^^^^^^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden
struct Foo<const N: usize>;
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: constant expression depends on a generic parameter
--> $DIR/unify-fixpoint.rs:9:32
error: type parameters with a default must be trailing
- --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:12
+ --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:12
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^
= note: using type defaults and const parameters in the same parameter list is currently not permitted
error: constant values inside of type parameter defaults must not depend on generic parameters
- --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
+ --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
|
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ the anonymous constant must not depend on the parameter `T`
error: constant values inside of type parameter defaults must not depend on generic parameters
- --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
+ --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ the anonymous constant must not depend on the parameter `N`
error: type parameters with a default must be trailing
- --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:12
+ --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:12
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^
= note: using type defaults and const parameters in the same parameter list is currently not permitted
error: generic parameters may not be used in const operations
- --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
+ --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:6:44
|
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ cannot perform const operation using `T`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: constant values inside of type parameter defaults must not depend on generic parameters
- --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
+ --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:11:21
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^ the anonymous constant must not depend on the parameter `N`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
//[full]~^ ERROR constant values inside of type parameter defaults
// run-pass
// tests that promoting expressions containing const parameters is allowed.
-#![feature(min_const_generics)]
-
fn promotion_test<const N: usize>() -> &'static usize {
&(3 + N)
}
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/raw-ptr-const-param-deref.rs:10:23
+ --> $DIR/raw-ptr-const-param-deref.rs:9:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/raw-ptr-const-param-deref.rs:12:15
+ --> $DIR/raw-ptr-const-param-deref.rs:11:15
|
LL | impl<const P: *const u32> Const<P> {
| ^^^^^^^^^^
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/raw-ptr-const-param-deref.rs:10:23
+ --> $DIR/raw-ptr-const-param-deref.rs:9:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/raw-ptr-const-param-deref.rs:12:15
+ --> $DIR/raw-ptr-const-param-deref.rs:11:15
|
LL | impl<const P: *const u32> Const<P> {
| ^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
const A: u32 = 3;
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/raw-ptr-const-param.rs:7:23
+ --> $DIR/raw-ptr-const-param.rs:6:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
error: using raw pointers as const generic parameters is forbidden
- --> $DIR/raw-ptr-const-param.rs:7:23
+ --> $DIR/raw-ptr-const-param.rs:6:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
error[E0308]: mismatched types
- --> $DIR/slice-const-param-mismatch.rs:15:35
+ --> $DIR/slice-const-param-mismatch.rs:14:35
|
LL | let _: ConstString<"Hello"> = ConstString::<"World">;
| -------------------- ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
found struct `ConstString<"World">`
error[E0308]: mismatched types
- --> $DIR/slice-const-param-mismatch.rs:17:33
+ --> $DIR/slice-const-param-mismatch.rs:16:33
|
LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
| ------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
found struct `ConstString<"ℇ㇈↥">`
error[E0308]: mismatched types
- --> $DIR/slice-const-param-mismatch.rs:19:33
+ --> $DIR/slice-const-param-mismatch.rs:18:33
|
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
| ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
error: `&'static str` is forbidden as the type of a const generic parameter
- --> $DIR/slice-const-param-mismatch.rs:8:29
+ --> $DIR/slice-const-param-mismatch.rs:7:29
|
LL | struct ConstString<const T: &'static str>;
| ^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static [u8]` is forbidden as the type of a const generic parameter
- --> $DIR/slice-const-param-mismatch.rs:10:28
+ --> $DIR/slice-const-param-mismatch.rs:9:28
|
LL | struct ConstBytes<const T: &'static [u8]>;
| ^^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct ConstString<const T: &'static str>;
error: `&'static str` is forbidden as the type of a const generic parameter
- --> $DIR/slice-const-param.rs:8:40
+ --> $DIR/slice-const-param.rs:7:40
|
LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
| ^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static [u8]` is forbidden as the type of a const generic parameter
- --> $DIR/slice-const-param.rs:13:41
+ --> $DIR/slice-const-param.rs:12:41
|
LL | pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
| ^^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub fn function_with_str<const STRING: &'static str>() -> &'static str {
//[min]~^ ERROR `&'static str` is forbidden
error: `std::ops::Range<usize>` is forbidden as the type of a const generic parameter
- --> $DIR/const-generics-range.rs:8:24
+ --> $DIR/const-generics-range.rs:7:24
|
LL | struct _Range<const R: std::ops::Range<usize>>;
| ^^^^^^^^^^^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `RangeFrom<usize>` is forbidden as the type of a const generic parameter
- --> $DIR/const-generics-range.rs:13:28
+ --> $DIR/const-generics-range.rs:12:28
|
LL | struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `RangeFull` is forbidden as the type of a const generic parameter
- --> $DIR/const-generics-range.rs:18:28
+ --> $DIR/const-generics-range.rs:17:28
|
LL | struct _RangeFull<const R: std::ops::RangeFull>;
| ^^^^^^^^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `RangeInclusive<usize>` is forbidden as the type of a const generic parameter
- --> $DIR/const-generics-range.rs:24:33
+ --> $DIR/const-generics-range.rs:23:33
|
LL | struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `RangeTo<usize>` is forbidden as the type of a const generic parameter
- --> $DIR/const-generics-range.rs:29:26
+ --> $DIR/const-generics-range.rs:28:26
|
LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `RangeToInclusive<usize>` is forbidden as the type of a const generic parameter
- --> $DIR/const-generics-range.rs:34:35
+ --> $DIR/const-generics-range.rs:33:35
|
LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
// `Range` should be usable within const generics:
struct _Range<const R: std::ops::Range<usize>>;
error[E0573]: expected type, found const parameter `C`
- --> $DIR/struct-with-invalid-const-param.rs:8:23
+ --> $DIR/struct-with-invalid-const-param.rs:7:23
|
LL | struct S<const C: u8>(C);
| ^ not a type
error[E0573]: expected type, found const parameter `C`
- --> $DIR/struct-with-invalid-const-param.rs:8:23
+ --> $DIR/struct-with-invalid-const-param.rs:7:23
|
LL | struct S<const C: u8>(C);
| ^ not a type
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct S<const C: u8>(C); //~ ERROR expected type, found const parameter
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Const<const N: usize>;
trait Foo<const N: usize> {}
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::mem::MaybeUninit;
error: type parameters must be declared prior to const parameters
- --> $DIR/type-after-const-ok.rs:9:26
+ --> $DIR/type-after-const-ok.rs:8:26
|
LL | struct A<const N: usize, T>(T);
| -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
// Verifies that having generic parameters after constants is permitted
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#[allow(dead_code)]
struct A<const N: usize, T>(T);
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub struct Struct<const N: usize>(());
// run-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(min, feature(min_const_generics))]
#![allow(incomplete_features)]
struct Foo;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait SliceExt<T: Clone> {
fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait T {
fn test<const A: i32>(&self) -> i32 { A }
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct X;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: usize>;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait IterExt: Sized + Iterator {
fn default_for_size<const N: usize>(self) -> [Self::Item; N]
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Struct<const N: usize>;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait ConstChunksExactTrait<T> {
fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, {N}>;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::marker::PhantomData;
error: `&'static str` is forbidden as the type of a const generic parameter
- --> $DIR/issue-71348.rs:11:24
+ --> $DIR/issue-71348.rs:10:24
|
LL | trait Get<'a, const N: &'static str> {
| ^^^^^^^^^^^^
= help: more complex types are supported with `#[feature(const_generics)]`
error: `&'static str` is forbidden as the type of a const generic parameter
- --> $DIR/issue-71348.rs:19:25
+ --> $DIR/issue-71348.rs:18:25
|
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
| ^^^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Foo {
i: i32,
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71382.rs:17:23
+ --> $DIR/issue-71382.rs:16:23
|
LL | fn test<const FN: fn() -> u8>(&self) -> u8 {
| ^^^^^^^^^^
error: using function pointers as const generic parameters is forbidden
- --> $DIR/issue-71382.rs:17:23
+ --> $DIR/issue-71382.rs:16:23
|
LL | fn test<const FN: fn() -> u8>(&self) -> u8 {
| ^^^^^^^^^^
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct Test;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::mem::MaybeUninit;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Foo<'a, A>: Iterator<Item=A> {
fn bar<const N: usize>(&mut self) -> *const [A; N];
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
extern crate type_dependent_lib;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A;
impl A {
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct R;
error[E0308]: mismatched types
- --> $DIR/type-mismatch.rs:12:27
+ --> $DIR/type-mismatch.rs:11:27
|
LL | assert_eq!(R.method::<1u16>(), 1);
| ^^^^ expected `u8`, found `u16`
error[E0308]: mismatched types
- --> $DIR/type-mismatch.rs:12:27
+ --> $DIR/type-mismatch.rs:11:27
|
LL | assert_eq!(R.method::<1u16>(), 1);
| ^^^^ expected `u8`, found `u16`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct R;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait T<const A: usize> {
fn l<const N: bool>() -> usize;
error[E0308]: mismatched types
- --> $DIR/types-mismatch-const-args.rs:15:41
+ --> $DIR/types-mismatch-const-args.rs:14:41
|
LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
found type `4_u32`
error[E0308]: mismatched types
- --> $DIR/types-mismatch-const-args.rs:17:41
+ --> $DIR/types-mismatch-const-args.rs:16:41
|
LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
| -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
error[E0308]: mismatched types
- --> $DIR/types-mismatch-const-args.rs:15:41
+ --> $DIR/types-mismatch-const-args.rs:14:41
|
LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
| -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
found struct `A<'_, _, 4_u32, _>`
error[E0308]: mismatched types
- --> $DIR/types-mismatch-const-args.rs:17:41
+ --> $DIR/types-mismatch-const-args.rs:16:41
|
LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
| -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
// tests the diagnostic output of type mismatches for types that have const generics arguments.
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::fmt;
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
use std::fmt;
error[E0412]: cannot find type `UnknownStruct` in this scope
- --> $DIR/unknown_adt.rs:8:12
+ --> $DIR/unknown_adt.rs:7:12
|
LL | let _: UnknownStruct<7>;
| ^^^^^^^^^^^^^ not found in this scope
error[E0412]: cannot find type `UnknownStruct` in this scope
- --> $DIR/unknown_adt.rs:8:12
+ --> $DIR/unknown_adt.rs:7:12
|
LL | let _: UnknownStruct<7>;
| ^^^^^^^^^^^^^ not found in this scope
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
fn main() {
let _: UnknownStruct<7>;
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: usize>; // ok
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![warn(unused_braces)]
warning: unnecessary braces around const expression
- --> $DIR/unused_braces.rs:15:14
+ --> $DIR/unused_braces.rs:14:14
|
LL | let _: A<{ 7 }>;
| ^^^^^ help: remove these braces
|
note: the lint level is defined here
- --> $DIR/unused_braces.rs:8:9
+ --> $DIR/unused_braces.rs:7:9
|
LL | #![warn(unused_braces)]
| ^^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![warn(unused_braces)]
warning: unnecessary braces around const expression
- --> $DIR/unused_braces.rs:15:14
+ --> $DIR/unused_braces.rs:14:14
|
LL | let _: A<{ 7 }>;
| ^^^^^ help: remove these braces
|
note: the lint level is defined here
- --> $DIR/unused_braces.rs:8:9
+ --> $DIR/unused_braces.rs:7:9
|
LL | #![warn(unused_braces)]
| ^^^^^^^^^^^^^
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
#![warn(unused_braces)]
error: constant expression depends on a generic parameter
- --> $DIR/wf-misc.rs:9:12
+ --> $DIR/wf-misc.rs:8:12
|
LL | let _: [u8; N + 1];
| ^^^^^^^^^^^
= note: this may fail depending on what value the parameter takes
error: constant expression depends on a generic parameter
- --> $DIR/wf-misc.rs:17:12
+ --> $DIR/wf-misc.rs:16:12
|
LL | let _: Const::<{N + 1}>;
| ^^^^^^^^^^^^^^^^
error: generic parameters may not be used in const operations
- --> $DIR/wf-misc.rs:9:17
+ --> $DIR/wf-misc.rs:8:17
|
LL | let _: [u8; N + 1];
| ^ cannot perform const operation using `N`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/wf-misc.rs:17:21
+ --> $DIR/wf-misc.rs:16:21
|
LL | let _: Const::<{N + 1}>;
| ^ cannot perform const operation using `N`
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
pub fn arr_len<const N: usize>() {
let _: [u8; N + 1];
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
trait Bar<const N: usize> { fn bar() {} }
trait Foo<const N: usize>: Bar<N> {}
--- /dev/null
+// error-pattern: any use of this value will cause an error
+
+#![feature(const_ptr_read)]
+#![feature(const_ptr_offset)]
+
+fn main() {
+ use std::ptr;
+
+ const DATA: [u32; 1] = [42];
+
+ const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) };
+
+ const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
+ const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
+ const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
+}
--- /dev/null
+error: any use of this value will cause an error
+ --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | unsafe { copy_nonoverlapping(src, dst, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
+ | inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ | inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
+ |
+ ::: $DIR/out_of_bounds_read.rs:13:5
+ |
+LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
+ | ------------------------------------------------------
+ |
+ = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+ --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | unsafe { copy_nonoverlapping(src, dst, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
+ | inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ | inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ | inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
+ |
+ ::: $DIR/out_of_bounds_read.rs:14:5
+ |
+LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
+ | --------------------------------------------------------
+
+error: any use of this value will cause an error
+ --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | unsafe { copy_nonoverlapping(src, dst, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
+ | inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ | inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+ | inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
+ |
+ ::: $DIR/out_of_bounds_read.rs:15:5
+ |
+LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
+ | --------------------------------------------------------------------
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+#![feature(const_fn)]
+
+const X : usize = 2;
+
+const fn f(x: usize) -> usize {
+ let mut sum = 0;
+ for i in 0..x {
+ //~^ ERROR mutable references
+ //~| ERROR calls in constant functions
+ //~| ERROR calls in constant functions
+ //~| ERROR E0080
+ //~| ERROR E0744
+ sum += i;
+ }
+ sum
+}
+
+#[allow(unused_variables)]
+fn main() {
+ let a : [i32; f(X)];
+}
--- /dev/null
+error[E0744]: `for` is not allowed in a `const fn`
+ --> $DIR/const-fn-error.rs:7:5
+ |
+LL | / for i in 0..x {
+LL | |
+LL | |
+LL | |
+... |
+LL | | sum += i;
+LL | | }
+ | |_____^
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/const-fn-error.rs:7:14
+ |
+LL | for i in 0..x {
+ | ^^^^
+
+error[E0658]: mutable references are not allowed in constant functions
+ --> $DIR/const-fn-error.rs:7:14
+ |
+LL | for i in 0..x {
+ | ^^^^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/const-fn-error.rs:7:14
+ |
+LL | for i in 0..x {
+ | ^^^^
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/const-fn-error.rs:7:14
+ |
+LL | for i in 0..x {
+ | ^^^^
+ | |
+ | calling non-const function `<std::ops::Range<usize> as IntoIterator>::into_iter`
+ | inside `f` at $DIR/const-fn-error.rs:7:14
+...
+LL | let a : [i32; f(X)];
+ | ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:20:19
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0015, E0080, E0658, E0744.
+For more information about an error, try `rustc --explain E0015`.
// run-pass
#![feature(const_size_of_val, const_align_of_val)]
+#![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)]
use std::mem;
const SIZE_OF_SLICE: usize = mem::size_of_val("foobar".as_bytes());
+const SIZE_OF_DANGLING: usize = unsafe { mem::size_of_val_raw(0x100 as *const i32) };
+const ALIGN_OF_DANGLING: usize = unsafe { mem::align_of_val_raw(0x100 as *const i16) };
+
fn main() {
assert_eq!(SIZE_OF_FOO, mem::size_of::<Foo>());
assert_eq!(SIZE_OF_BAR, mem::size_of::<Bar>());
assert_eq!(ALIGN_OF_BAR, mem::align_of::<Bar>());
assert_eq!(ALIGN_OF_UGH, mem::align_of::<Ugh>());
+ assert_eq!(SIZE_OF_DANGLING, mem::size_of::<i32>());
+ assert_eq!(ALIGN_OF_DANGLING, mem::align_of::<i16>());
+
assert_eq!(SIZE_OF_SLICE, "foobar".len());
}
--- /dev/null
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+struct Foo {
+ bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+ //~^ ERROR cycle detected when simplifying constant for the type system
+ x: usize,
+}
+
+fn main() {}
--- /dev/null
+error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{constant#0}`
+ --> $DIR/issue-44415.rs:6:17
+ |
+LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+ | ^^^^^^
+ |
+note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`...
+ --> $DIR/issue-44415.rs:6:17
+ |
+LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+ | ^^^^^^
+note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
+ --> $DIR/issue-44415.rs:6:17
+ |
+LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+ | ^^^^^^
+ = note: ...which requires computing layout of `Foo`...
+ = note: ...which requires normalizing `[u8; _]`...
+ = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle
+note: cycle used when checking that `Foo` is well-formed
+ --> $DIR/issue-44415.rs:5:1
+ |
+LL | struct Foo {
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0391`.
--- /dev/null
+// build-fail
+// normalize-stderr-64bit "18446744073709551615" -> "SIZE"
+// normalize-stderr-32bit "4294967295" -> "SIZE"
+
+// error-pattern: are too big for the current architecture
+fn main() {
+ println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
+}
--- /dev/null
+error[E0080]: values of the type `[u8; SIZE]` are too big for the current architecture
+ --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ |
+LL | intrinsics::size_of::<T>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ | inside `main` at $DIR/issue-55878.rs:7:26
+ |
+ ::: $DIR/issue-55878.rs:7:26
+ |
+LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
+ | ----------------------------------------------
+
+error: erroneous constant used
+ --> $DIR/issue-55878.rs:7:26
+ |
+LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+ |
+ = note: `#[deny(const_err)]` on by default
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// compile-flags:-C extra-filename=-1
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 10 }
--- /dev/null
+// compile-flags:-C extra-filename=-2
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 20 }
--- /dev/null
+// compile-flags:-C extra-filename=-3
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 30 }
--- /dev/null
+// dont-check-compiler-stderr
+// aux-build:crateresolve1-1.rs
+// aux-build:crateresolve1-2.rs
+// aux-build:crateresolve1-3.rs
+// error-pattern:multiple matching crates for `crateresolve1`
+
+extern crate crateresolve1;
+
+fn main() {
+}
// Reject mixing cyclic structure and Drop when using trait
// objects to hide the cross-references.
//
-// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+// (Compare against ui/span/dropck_vec_cycle_checked.rs)
use std::cell::Cell;
use id::Id;
// Issue 8142: Test that Drop impls cannot be specialized beyond the
// predicates attached to the type definition itself.
-#![feature(min_const_generics)]
-
trait Bound { fn foo(&self) { } }
struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
- --> $DIR/reject-specialized-drops-8142.rs:26:20
+ --> $DIR/reject-specialized-drops-8142.rs:24:20
|
LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
| ^^^
|
note: the implementor must specify the same requirement
- --> $DIR/reject-specialized-drops-8142.rs:6:1
+ --> $DIR/reject-specialized-drops-8142.rs:4:1
|
LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
- --> $DIR/reject-specialized-drops-8142.rs:30:67
+ --> $DIR/reject-specialized-drops-8142.rs:28:67
|
LL | impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
| ^^^
|
note: the implementor must specify the same requirement
- --> $DIR/reject-specialized-drops-8142.rs:7:1
+ --> $DIR/reject-specialized-drops-8142.rs:5:1
|
LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
- --> $DIR/reject-specialized-drops-8142.rs:36:1
+ --> $DIR/reject-specialized-drops-8142.rs:34:1
|
LL | impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected struct `N<'n>`
found struct `N<'static>`
-note: the lifetime `'n` as defined on the struct at 9:10...
- --> $DIR/reject-specialized-drops-8142.rs:9:10
+note: the lifetime `'n` as defined on the struct at 7:10...
+ --> $DIR/reject-specialized-drops-8142.rs:7:10
|
LL | struct N<'n> { x: &'n i8 }
| ^^
= note: ...does not necessarily outlive the static lifetime
error[E0366]: `Drop` impls cannot be specialized
- --> $DIR/reject-specialized-drops-8142.rs:43:1
+ --> $DIR/reject-specialized-drops-8142.rs:41:1
|
LL | impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: use the same sequence of generic type, lifetime and const parameters as the struct definition
- --> $DIR/reject-specialized-drops-8142.rs:11:1
+ --> $DIR/reject-specialized-drops-8142.rs:9:1
|
LL | struct P<Tp> { x: *const Tp }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
- --> $DIR/reject-specialized-drops-8142.rs:46:14
+ --> $DIR/reject-specialized-drops-8142.rs:44:14
|
LL | impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
|
note: the implementor must specify the same requirement
- --> $DIR/reject-specialized-drops-8142.rs:12:1
+ --> $DIR/reject-specialized-drops-8142.rs:10:1
|
LL | struct Q<Tq> { x: *const Tq }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not
- --> $DIR/reject-specialized-drops-8142.rs:49:21
+ --> $DIR/reject-specialized-drops-8142.rs:47:21
|
LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
|
note: the implementor must specify the same requirement
- --> $DIR/reject-specialized-drops-8142.rs:13:1
+ --> $DIR/reject-specialized-drops-8142.rs:11:1
|
LL | struct R<Tr> { x: *const Tr }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
- --> $DIR/reject-specialized-drops-8142.rs:58:1
+ --> $DIR/reject-specialized-drops-8142.rs:56:1
|
LL | impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: use the same sequence of generic type, lifetime and const parameters as the struct definition
- --> $DIR/reject-specialized-drops-8142.rs:17:1
+ --> $DIR/reject-specialized-drops-8142.rs:15:1
|
LL | struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'lw` due to conflicting requirements
- --> $DIR/reject-specialized-drops-8142.rs:61:1
+ --> $DIR/reject-specialized-drops-8142.rs:59:1
|
LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 18:10...
- --> $DIR/reject-specialized-drops-8142.rs:18:10
+note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 16:10...
+ --> $DIR/reject-specialized-drops-8142.rs:16:10
|
LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
| ^^^
-note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 18:15...
- --> $DIR/reject-specialized-drops-8142.rs:18:15
+note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 16:15...
+ --> $DIR/reject-specialized-drops-8142.rs:16:15
|
LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
| ^^^
note: ...so that the types are compatible
- --> $DIR/reject-specialized-drops-8142.rs:61:1
+ --> $DIR/reject-specialized-drops-8142.rs:59:1
|
LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
found `W<'_, '_>`
error[E0366]: `Drop` impls cannot be specialized
- --> $DIR/reject-specialized-drops-8142.rs:64:1
+ --> $DIR/reject-specialized-drops-8142.rs:62:1
|
LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: use the same sequence of generic type, lifetime and const parameters as the struct definition
- --> $DIR/reject-specialized-drops-8142.rs:19:1
+ --> $DIR/reject-specialized-drops-8142.rs:17:1
|
LL | struct X<const Ca: usize>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0366]: `Drop` impls cannot be specialized
- --> $DIR/reject-specialized-drops-8142.rs:67:1
+ --> $DIR/reject-specialized-drops-8142.rs:65:1
|
LL | impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: use the same sequence of generic type, lifetime and const parameters as the struct definition
- --> $DIR/reject-specialized-drops-8142.rs:20:1
+ --> $DIR/reject-specialized-drops-8142.rs:18:1
|
LL | struct Y<const Ca: usize, const Cb: usize>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
- --> $DIR/reject-specialized-drops-8142.rs:70:14
+ --> $DIR/reject-specialized-drops-8142.rs:68:14
|
LL | impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
|
note: the implementor must specify the same requirement
- --> $DIR/reject-specialized-drops-8142.rs:22:1
+ --> $DIR/reject-specialized-drops-8142.rs:20:1
|
LL | enum Enum<T> { Variant(T) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
- --> $DIR/reject-specialized-drops-8142.rs:73:14
+ --> $DIR/reject-specialized-drops-8142.rs:71:14
|
LL | impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
|
note: the implementor must specify the same requirement
- --> $DIR/reject-specialized-drops-8142.rs:23:1
+ --> $DIR/reject-specialized-drops-8142.rs:21:1
|
LL | struct TupleStruct<T>(T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
- --> $DIR/reject-specialized-drops-8142.rs:76:21
+ --> $DIR/reject-specialized-drops-8142.rs:74:21
|
LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
| ^^^^^
|
note: the implementor must specify the same requirement
- --> $DIR/reject-specialized-drops-8142.rs:24:1
+ --> $DIR/reject-specialized-drops-8142.rs:22:1
|
LL | union Union<T: Copy> { f: T }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
enum MyWeirdOption<T> {
None = 0,
Some(T) = std::mem::size_of::<T>(),
- //~^ ERROR constant expression depends on a generic parameter
+ //~^ ERROR generic parameters may not be used in const operations
}
fn main() {
-error: constant expression depends on a generic parameter
- --> $DIR/issue-70453-generics-in-discr-ice-2.rs:9:15
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-70453-generics-in-discr-ice-2.rs:9:35
|
LL | Some(T) = std::mem::size_of::<T>(),
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^ cannot perform const operation using `T`
|
- = note: this may fail depending on what value the parameter takes
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
//~^ ERROR parameter `T` is never used
None = 0,
Some = std::mem::size_of::<T>(),
- //~^ ERROR constant expression depends on a generic parameter
+ //~^ ERROR generic parameters may not be used in const operations
}
fn main() {
-error: constant expression depends on a generic parameter
- --> $DIR/issue-70453-generics-in-discr-ice.rs:10:12
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-70453-generics-in-discr-ice.rs:10:32
|
LL | Some = std::mem::size_of::<T>(),
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^ cannot perform const operation using `T`
|
- = note: this may fail depending on what value the parameter takes
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error[E0392]: parameter `T` is never used
--> $DIR/issue-70453-generics-in-discr-ice.rs:7:20
-// run-pass
#![feature(arbitrary_enum_discriminant, core_intrinsics)]
extern crate core;
enum MyWeirdOption<T> {
None = 0,
Some(T) = core::mem::size_of::<*mut T>(),
- //~^ WARN cannot use constants which depend on generic parameters in types
- //~| WARN this was previously accepted by the compiler but is being phased out
+ //~^ ERROR generic parameters may not be used
}
fn main() {
-warning: cannot use constants which depend on generic parameters in types
- --> $DIR/issue-70453-polymorphic-ctfe.rs:10:15
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-70453-polymorphic-ctfe.rs:9:41
|
LL | Some(T) = core::mem::size_of::<*mut T>(),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^ cannot perform const operation using `T`
|
- = note: `#[warn(const_evaluatable_unchecked)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-warning: 1 warning emitted
+error: aborting due to previous error
-enum Bug<S> {
+enum Bug<S> { //~ ERROR parameter `S` is never used
Var = {
- let x: S = 0; //~ ERROR: mismatched types
+ let x: S = 0; //~ ERROR generic parameters may not be used
0
},
}
-error[E0308]: mismatched types
- --> $DIR/issue-67945-1.rs:3:20
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-67945-1.rs:3:16
|
-LL | enum Bug<S> {
- | - this type parameter
-LL | Var = {
LL | let x: S = 0;
- | - ^ expected type parameter `S`, found integer
- | |
- | expected due to this
+ | ^ cannot perform const operation using `S`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error[E0392]: parameter `S` is never used
+ --> $DIR/issue-67945-1.rs:1:10
+ |
+LL | enum Bug<S> {
+ | ^ unused parameter
|
- = note: expected type parameter `S`
- found type `{integer}`
+ = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-error: aborting due to previous error
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0392`.
#![feature(type_ascription)]
-enum Bug<S> {
+enum Bug<S> { //~ ERROR parameter `S` is never used
Var = 0: S,
- //~^ ERROR: mismatched types
- //~| ERROR: mismatched types
+ //~^ ERROR generic parameters may not be used
}
fn main() {}
-error[E0308]: mismatched types
- --> $DIR/issue-67945-2.rs:4:11
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-67945-2.rs:4:14
|
-LL | enum Bug<S> {
- | - this type parameter
LL | Var = 0: S,
- | ^ expected type parameter `S`, found integer
+ | ^ cannot perform const operation using `S`
|
- = note: expected type parameter `S`
- found type `{integer}`
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
-error[E0308]: mismatched types
- --> $DIR/issue-67945-2.rs:4:11
+error[E0392]: parameter `S` is never used
+ --> $DIR/issue-67945-2.rs:3:10
|
LL | enum Bug<S> {
- | - this type parameter
-LL | Var = 0: S,
- | ^^^^ expected `isize`, found type parameter `S`
+ | ^ unused parameter
|
- = note: expected type `isize`
- found type parameter `S`
+ = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0392`.
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error[E0730]: cannot pattern-match on an array without a fixed length
--> $DIR/E0730.rs:6:9
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error[E0771]: use of non-static lifetime `'a` in const generic
--> $DIR/E0771.rs:4:41
--- /dev/null
+// compile-flags: --extern std=
+// error-pattern: extern location for std does not exist
+
+fn main() {}
--- /dev/null
+error: extern location for std does not exist:
+
+error: aborting due to previous error
+
+++ /dev/null
-struct ConstFn<const F: fn()>;
-//~^ ERROR const generics are unstable
-//~^^ ERROR using function pointers as const generic parameters is forbidden
-
-struct ConstPtr<const P: *const u32>;
-//~^ ERROR const generics are unstable
-//~^^ ERROR using raw pointers as const generic parameters is forbidden
-
-fn main() {}
+++ /dev/null
-error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics-ptr.rs:1:22
- |
-LL | struct ConstFn<const F: fn()>;
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics-ptr.rs:5:23
- |
-LL | struct ConstPtr<const P: *const u32>;
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: using function pointers as const generic parameters is forbidden
- --> $DIR/feature-gate-const_generics-ptr.rs:1:25
- |
-LL | struct ConstFn<const F: fn()>;
- | ^^^^
-
-error: using raw pointers as const generic parameters is forbidden
- --> $DIR/feature-gate-const_generics-ptr.rs:5:26
- |
-LL | struct ConstPtr<const P: *const u32>;
- | ^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
-fn foo<const X: ()>() {} //~ ERROR const generics are unstable
+fn foo<const X: ()>() {} //~ ERROR `()` is forbidden as the type of a const generic parameter
-struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
+struct Foo<const X: usize>([(); X]);
fn main() {}
-error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics.rs:1:14
+error: `()` is forbidden as the type of a const generic parameter
+ --> $DIR/feature-gate-const_generics.rs:1:17
|
LL | fn foo<const X: ()>() {}
- | ^
+ | ^^
|
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
+ = note: the only supported types are integers, `bool` and `char`
+ = help: more complex types are supported with `#[feature(const_generics)]`
-error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics.rs:3:18
- |
-LL | struct Foo<const X: usize>([(); X]);
- | ^
- |
- = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
- = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Functions with a type placeholder `_` as the return type should
+// show a function pointer suggestion when given a function item
+// and suggest how to return closures correctly from a function.
+// This is a regression test of #80179
+
+fn returns_i32() -> i32 {
+ 0
+}
+
+fn returns_fn_ptr() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
+//~| NOTE not allowed in type signatures
+//~| HELP replace with the correct return type
+//~| SUGGESTION fn() -> i32
+ returns_i32
+}
+
+fn returns_closure() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
+//~| NOTE not allowed in type signatures
+//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
+//~| NOTE for more information on `Fn` traits and closure types, see
+// https://doc.rust-lang.org/book/ch13-01-closures.html
+ || 0
+}
+
+fn main() {}
--- /dev/null
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/issue-80179.rs:10:24
+ |
+LL | fn returns_fn_ptr() -> _ {
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with the correct return type: `fn() -> i32`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/issue-80179.rs:18:25
+ |
+LL | fn returns_closure() -> _ {
+ | ^ not allowed in type signatures
+ |
+ = help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
+ = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
fn test0() {
// just copy implicitly copyable fields from `f`, no moves
// (and thus it is okay that these are Drop; compare against
- // compile-fail test: borrowck-struct-update-with-dtor.rs).
+ // test ui/borrowck/borrowck-struct-update-with-dtor.rs).
// Case 1: Nocopyable
let f = DropNoFoo::new(1, 2);
some pretty deep flaws in the ad-hoc way that we were doing things
before.
-See also `src/test/compile-fail/closure-expected-type`.
+See also `src/test/ui/closure-expected-type`.
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+#![allow(incomplete_features)]
+
+use std::ops::Deref;
+
+trait UnsafeCopy {
+ type Copy<T>: Copy = Box<T>;
+ //~^ ERROR the trait bound `Box<T>: Copy` is not satisfied
+ //~^^ ERROR the trait bound `T: Clone` is not satisfied
+ fn copy<T>(x: &Self::Copy<T>) -> Self::Copy<T> {
+ *x
+ }
+}
+
+impl<T> UnsafeCopy for T {}
+
+fn main() {
+ let b = Box::new(42usize);
+ let copy = <()>::copy(&b);
+
+ let raw_b = Box::deref(&b) as *const _;
+ let raw_copy = Box::deref(©) as *const _;
+
+ // assert the addresses.
+ assert_eq!(raw_b, raw_copy);
+}
--- /dev/null
+error[E0277]: the trait bound `Box<T>: Copy` is not satisfied
+ --> $DIR/issue-74824.rs:8:5
+ |
+LL | type Copy<T>: Copy = Box<T>;
+ | ^^^^^^^^^^^^^^----^^^^^^^^^^
+ | | |
+ | | required by this bound in `UnsafeCopy::Copy`
+ | the trait `Copy` is not implemented for `Box<T>`
+
+error[E0277]: the trait bound `T: Clone` is not satisfied
+ --> $DIR/issue-74824.rs:8:5
+ |
+LL | type Copy<T>: Copy = Box<T>;
+ | ^^^^^^^^^^^^^^----^^^^^^^^^^
+ | | |
+ | | required by this bound in `UnsafeCopy::Copy`
+ | the trait `Clone` is not implemented for `T`
+ |
+ = note: required because of the requirements on the impl of `Clone` for `Box<T>`
+help: consider restricting type parameter `T`
+ |
+LL | type Copy<T: Clone>: Copy = Box<T>;
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
-//~^ ERROR constant values inside of type parameter defaults
+//~^ ERROR generic parameters may not be used in const operations
fn main() {}
-error: constant values inside of type parameter defaults must not depend on generic parameters
+error: generic parameters may not be used in const operations
--> $DIR/param-in-ct-in-ty-param-default.rs:1:44
|
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
- | ^ the anonymous constant must not depend on the parameter `T`
+ | ^ cannot perform const operation using `T`
+ |
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: 1 warning emitted
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: 1 warning emitted
LL | fn iceman(c: Vec<[i32]>) {}
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
- ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
+ ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| - required by this bound in `Vec`
// run-pass
-#![allow(unused_imports, overlapping_patterns)]
+#![allow(unused_imports, overlapping_range_endpoints)]
// pretty-expanded FIXME #23616
use m::{START, END};
-error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
+error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next`
--> $DIR/issue-23122-2.rs:9:5
|
LL | type Next = <GetNext<T::Next> as Next>::Next;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`)
- = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
error: aborting due to previous error
// run-pass
-#![allow(overlapping_patterns)]
+#![allow(overlapping_range_endpoints)]
fn main() {
let x = 'a';
// run-pass
-// This test is bogus (i.e., should be compile-fail) during the period
+// This test is bogus (i.e., should be check-fail) during the period
// where #54986 is implemented and #54987 is *not* implemented. For
// now: just ignore it
//
// run-pass
-// This test is bogus (i.e., should be compile-fail) during the period
+// This test is bogus (i.e., should be check-fail) during the period
// where #54986 is implemented and #54987 is *not* implemented. For
// now: just ignore it
//
// Demonstrate the use of the unguarded escape hatch with a lifetime param
// to assert that destructor will not access any dead data.
//
-// Compare with compile-fail/issue28498-reject-lifetime-param.rs
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
#![feature(dropck_eyepatch)]
// Demonstrate the use of the unguarded escape hatch with a type param in negative position
// to assert that destructor will not access any dead data.
//
-// Compare with compile-fail/issue28498-reject-lifetime-param.rs
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
// Demonstrate that a type param in negative position causes dropck to reject code
// that might indirectly access previously dropped value.
// Demonstrate the use of the unguarded escape hatch with a trait bound
// to assert that destructor will not access any dead data.
//
-// Compare with compile-fail/issue28498-reject-trait-bound.rs
+// Compare with ui/span/issue28498-reject-trait-bound.rs
#![feature(dropck_eyepatch)]
pub struct Vector<T, D: Dim> {
entries: [T; D::dim()],
- //~^ ERROR no function or associated item named `dim` found
+ //~^ ERROR generic parameters may not be used
_dummy: D,
}
-error[E0599]: no function or associated item named `dim` found for type parameter `D` in the current scope
- --> $DIR/issue-39559.rs:14:21
+error: generic parameters may not be used in const operations
+ --> $DIR/issue-39559.rs:14:18
|
LL | entries: [T; D::dim()],
- | ^^^ function or associated item not found in `D`
+ | ^^^^^^ cannot perform const operation using `D`
|
- = help: items from traits can only be used if the type parameter is bounded by the trait
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0599`.
+++ /dev/null
-#![feature(const_fn)]
-#![feature(thread_local)]
-#![feature(cfg_target_thread_local, thread_local_internals)]
-
-type Foo = std::cell::RefCell<String>;
-
-#[cfg(target_thread_local)]
-#[thread_local]
-static __KEY: std::thread::__FastLocalKeyInner<Foo> =
- std::thread::__FastLocalKeyInner::new();
-
-#[cfg(not(target_thread_local))]
-static __KEY: std::thread::__OsLocalKeyInner<Foo> =
- std::thread::__OsLocalKeyInner::new();
-
-fn __getit() -> std::option::Option<&'static Foo>
-{
- __KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
-}
-
-static FOO: std::thread::LocalKey<Foo> =
- std::thread::LocalKey::new(__getit);
-//~^ ERROR call to unsafe function is unsafe
-
-fn main() {
- FOO.with(|foo| println!("{}", foo.borrow()));
- std::thread::spawn(|| {
- FOO.with(|foo| *foo.borrow_mut() += "foo");
- }).join().unwrap();
- FOO.with(|foo| println!("{}", foo.borrow()));
-}
+++ /dev/null
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:18:5
- |
-LL | __KEY.get(Default::default)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:22:5
- |
-LL | std::thread::LocalKey::new(__getit);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
#![feature(test)]
#![allow(unused_mut)] // under NLL we get warning about `x` below: rust-lang/rust#54499
-// This test is bogus (i.e., should be compile-fail) during the period
+// This test is bogus (i.e., should be check-fail) during the period
// where #54986 is implemented and #54987 is *not* implemented. For
// now: just ignore it
//
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: aborting due to previous error; 1 warning emitted
--> $DIR/issue-59508.rs:10:25
|
LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then types: `<'a, 'b: 'a, T>`
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
error: aborting due to previous error
fn test<T>() {
let _: [u8; sof::<T>()];
- //~^ ERROR the size for values of type `T`
+ //~^ ERROR generic parameters may not be used in const operations
}
fn main() {}
-error[E0277]: the size for values of type `T` cannot be known at compilation time
+error: generic parameters may not be used in const operations
--> $DIR/feature-gate-lazy_normalization_consts.rs:6:23
|
-LL | pub const fn sof<T>() -> usize {
- | - required by this bound in `sof`
-...
-LL | fn test<T>() {
- | - this type parameter needs to be `Sized`
LL | let _: [u8; sof::<T>()];
- | ^ doesn't have a size known at compile-time
+ | ^ cannot perform const operation using `T`
|
-help: consider relaxing the implicit `Sized` restriction
- |
-LL | pub const fn sof<T: ?Sized>() -> usize {
- | ^^^^^^^^
+ = note: type parameters may not be used in const expressions
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
--> $DIR/lifetime-before-type-params.rs:2:13
|
LL | fn first<T, 'a, 'b>() {}
- | ----^^--^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+ | ----^^--^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/lifetime-before-type-params.rs:4:18
|
LL | fn second<'a, T, 'b>() {}
- | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/lifetime-before-type-params.rs:6:16
|
LL | fn third<T, U, 'a>() {}
- | -------^^- help: reorder the parameters: lifetimes, then types: `<'a, T, U>`
+ | -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/lifetime-before-type-params.rs:8:18
|
LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
- | --------^^-----^^---- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
+ | --------^^-----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>`
error: aborting due to 4 previous errors
--- /dev/null
+// build-fail
+// dont-check-compiler-stderr
+// ignore-msvc due to linker-flavor=ld
+// error-pattern:aFdEfSeVEEE
+// compile-flags: -C linker-flavor=ld
+
+/* Make sure invalid link_args are printed to stderr. */
+
+#![feature(link_args)]
+
+#[link_args = "aFdEfSeVEEE"]
+extern {}
+
+fn main() { }
--- /dev/null
+// build-fail
+// dont-check-compiler-stderr
+// compile-flags: -C linker=llllll -C linker-flavor=ld
+// error-pattern: linker `llllll` not found
+
+fn main() {
+}
( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator
}
+#[warn(missing_fragment_specifier)]
+macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier
+ //~| WARN this was previously accepted
+
#[warn(soft_unstable)]
mod benches {
#[bench] //~ WARN use of unstable library feature 'test'
LL | #[warn(meta_variable_misuse)]
| ^^^^^^^^^^^^^^^^^^^^
+warning: missing fragment specifier
+ --> $DIR/expansion-time.rs:9:19
+ |
+LL | macro_rules! m { ($i) => {} }
+ | ^^
+ |
+note: the lint level is defined here
+ --> $DIR/expansion-time.rs:8:8
+ |
+LL | #[warn(missing_fragment_specifier)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+
warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable
- --> $DIR/expansion-time.rs:10:7
+ --> $DIR/expansion-time.rs:14:7
|
LL | #[bench]
| ^^^^^
|
note: the lint level is defined here
- --> $DIR/expansion-time.rs:8:8
+ --> $DIR/expansion-time.rs:12:8
|
LL | #[warn(soft_unstable)]
| ^^^^^^^^^^^^^
| ^
|
note: the lint level is defined here
- --> $DIR/expansion-time.rs:25:8
+ --> $DIR/expansion-time.rs:29:8
|
LL | #[warn(incomplete_include)]
| ^^^^^^^^^^^^^^^^^^
-warning: 3 warnings emitted
+warning: 4 warnings emitted
// check-pass
-#![feature(c_variadic, min_const_generics)]
+#![feature(c_variadic)]
#![warn(function_item_references)]
use std::fmt::Pointer;
use std::fmt::Formatter;
= note: each usage of a `const` item creates a new temporary
= note: the mutable reference will refer to this temporary, not the original `const` item
note: mutable reference created due to call to this method
- --> $SRC_DIR/alloc/src/vec.rs:LL:COL
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
LL | / pub fn push(&mut self, value: T) {
LL | | // This will panic or abort if we would allocate > isize::MAX bytes
--- /dev/null
+#![deny(unused_must_use)]
+#![feature(arbitrary_self_types)]
+
+use std::iter::Iterator;
+use std::future::Future;
+
+use std::task::{Context, Poll};
+use std::pin::Pin;
+use std::unimplemented;
+
+struct MyFuture;
+
+impl Future for MyFuture {
+ type Output = u32;
+
+ fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<u32> {
+ Poll::Pending
+ }
+}
+
+fn iterator() -> impl Iterator {
+ std::iter::empty::<u32>()
+}
+
+fn future() -> impl Future {
+ MyFuture
+}
+
+fn square_fn_once() -> impl FnOnce(u32) -> u32 {
+ |x| x * x
+}
+
+fn square_fn_mut() -> impl FnMut(u32) -> u32 {
+ |x| x * x
+}
+
+fn square_fn() -> impl Fn(u32) -> u32 {
+ |x| x * x
+}
+
+fn main() {
+ iterator(); //~ ERROR unused implementer of `Iterator` that must be used
+ future(); //~ ERROR unused implementer of `Future` that must be used
+ square_fn_once(); //~ ERROR unused implementer of `FnOnce` that must be used
+ square_fn_mut(); //~ ERROR unused implementer of `FnMut` that must be used
+ square_fn(); //~ ERROR unused implementer of `Fn` that must be used
+}
--- /dev/null
+error: unused implementer of `Iterator` that must be used
+ --> $DIR/must_use-in-stdlib-traits.rs:42:4
+ |
+LL | iterator();
+ | ^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/must_use-in-stdlib-traits.rs:1:9
+ |
+LL | #![deny(unused_must_use)]
+ | ^^^^^^^^^^^^^^^
+ = note: iterators are lazy and do nothing unless consumed
+
+error: unused implementer of `Future` that must be used
+ --> $DIR/must_use-in-stdlib-traits.rs:43:4
+ |
+LL | future();
+ | ^^^^^^^^^
+ |
+ = note: futures do nothing unless you `.await` or poll them
+
+error: unused implementer of `FnOnce` that must be used
+ --> $DIR/must_use-in-stdlib-traits.rs:44:4
+ |
+LL | square_fn_once();
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: closures are lazy and do nothing unless called
+
+error: unused implementer of `FnMut` that must be used
+ --> $DIR/must_use-in-stdlib-traits.rs:45:4
+ |
+LL | square_fn_mut();
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: closures are lazy and do nothing unless called
+
+error: unused implementer of `Fn` that must be used
+ --> $DIR/must_use-in-stdlib-traits.rs:46:4
+ |
+LL | square_fn();
+ | ^^^^^^^^^^^^
+ |
+ = note: closures are lazy and do nothing unless called
+
+error: aborting due to 5 previous errors
+
-// check-pass
-// This test should stop compiling
-// we decide to enable this lint for item statements.
-
#![deny(redundant_semicolons)]
fn main() {
- fn inner() {};
- struct Bar {};
+ fn inner() {}; //~ ERROR unnecessary
+ struct Bar {}; //~ ERROR unnecessary
}
--- /dev/null
+error: unnecessary trailing semicolon
+ --> $DIR/item-stmt-semi.rs:4:18
+ |
+LL | fn inner() {};
+ | ^ help: remove this semicolon
+ |
+note: the lint level is defined here
+ --> $DIR/item-stmt-semi.rs:1:9
+ |
+LL | #![deny(redundant_semicolons)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unnecessary trailing semicolon
+ --> $DIR/item-stmt-semi.rs:5:18
+ |
+LL | struct Bar {};
+ | ^ help: remove this semicolon
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// build-fail
+// dont-check-compiler-stderr
+// compile-flags: -C codegen-units=2
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+
+fn main() {
+ unsafe {
+ llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
+ }
+}
--- /dev/null
+// build-fail
+// dont-check-compiler-stderr
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+
+fn main() {
+ unsafe {
+ llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
+ }
+}
macro_rules! m { ($i) => {} }
//~^ ERROR missing fragment specifier
+//~| WARN previously accepted
fn main() {}
|
LL | macro_rules! m { ($i) => {} }
| ^^
+ |
+ = note: `#[deny(missing_fragment_specifier)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
error: aborting due to previous error
// to it being e.g., a place where the addition of an argument
// causes it to go down a code path with subtly different behavior).
//
-// There is a companion test in compile-fail.
+// There is a companion failing test.
// compile-flags: --test -C debug_assertions=yes
// revisions: std core
assert!(true, "{}",);
- // assert_eq!(1, 1, "{}",); // see compile-fail
- // assert_ne!(1, 2, "{}",); // see compile-fail
+ // assert_eq!(1, 1, "{}",); // see check-fail
+ // assert_ne!(1, 2, "{}",); // see check-fail
debug_assert!(true, "{}",);
- // debug_assert_eq!(1, 1, "{}",); // see compile-fail
- // debug_assert_ne!(1, 2, "{}",); // see compile-fail
- // eprint!("{}",); // see compile-fail
- // eprintln!("{}",); // see compile-fail
- // format!("{}",); // see compile-fail
- // format_args!("{}",); // see compile-fail
+ // debug_assert_eq!(1, 1, "{}",); // see check-fail
+ // debug_assert_ne!(1, 2, "{}",); // see check-fail
+ // eprint!("{}",); // see check-fail
+ // eprintln!("{}",); // see check-fail
+ // format!("{}",); // see check-fail
+ // format_args!("{}",); // see check-fail
if falsum() { panic!("{}",); }
- // print!("{}",); // see compile-fail
- // println!("{}",); // see compile-fail
- // unimplemented!("{}",); // see compile-fail
+ // print!("{}",); // see check-fail
+ // println!("{}",); // see check-fail
+ // unimplemented!("{}",); // see check-fail
if falsum() { unreachable!("{}",); }
- // write!(&mut stdout, "{}",); // see compile-fail
- // writeln!(&mut stdout, "{}",); // see compile-fail
+ // write!(&mut stdout, "{}",); // see check-fail
+ // writeln!(&mut stdout, "{}",); // see check-fail
}
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:54:19
+ --> $DIR/macro-comma-behavior.rs:52:19
|
LL | format_args!("{}",);
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:72:21
+ --> $DIR/macro-comma-behavior.rs:68:21
|
LL | unimplemented!("{}",);
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:81:24
+ --> $DIR/macro-comma-behavior.rs:77:24
|
LL | write!(f, "{}",)?;
| ^^
-error: aborting due to 7 previous errors
+error: 1 positional argument in format string, but no arguments were given
+ --> $DIR/macro-comma-behavior.rs:81:26
+ |
+LL | writeln!(f, "{}",)?;
+ | ^^
+
+error: aborting due to 8 previous errors
}
#[cfg(std)] {
- // FIXME: compile-fail says "expected error not found" even though
- // rustc does emit an error
- // eprintln!("{}",);
- // <DISABLED> [std]~^ ERROR no arguments
+ eprintln!("{}",);
+ //[std]~^ ERROR no arguments
}
#[cfg(std)] {
}
#[cfg(std)] {
- // FIXME: compile-fail says "expected error not found" even though
- // rustc does emit an error
- // println!("{}",);
- // <DISABLED> [std]~^ ERROR no arguments
+ println!("{}",);
+ //[std]~^ ERROR no arguments
}
unimplemented!("{}",);
//[core]~^ ERROR no arguments
//[std]~^^ ERROR no arguments
- // FIXME: compile-fail says "expected error not found" even though
- // rustc does emit an error
- // writeln!(f, "{}",)?;
- // <DISABLED> [core]~^ ERROR no arguments
- // <DISABLED> [std]~^^ ERROR no arguments
+ writeln!(f, "{}",)?;
+ //[core]~^ ERROR no arguments
+ //[std]~^^ ERROR no arguments
Ok(())
}
}
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:50:18
+ --> $DIR/macro-comma-behavior.rs:43:20
+ |
+LL | eprintln!("{}",);
+ | ^^
+
+error: 1 positional argument in format string, but no arguments were given
+ --> $DIR/macro-comma-behavior.rs:48:18
|
LL | format!("{}",);
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:54:19
+ --> $DIR/macro-comma-behavior.rs:52:19
|
LL | format_args!("{}",);
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:61:17
+ --> $DIR/macro-comma-behavior.rs:59:17
|
LL | print!("{}",);
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:72:21
+ --> $DIR/macro-comma-behavior.rs:64:19
+ |
+LL | println!("{}",);
+ | ^^
+
+error: 1 positional argument in format string, but no arguments were given
+ --> $DIR/macro-comma-behavior.rs:68:21
|
LL | unimplemented!("{}",);
| ^^
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/macro-comma-behavior.rs:81:24
+ --> $DIR/macro-comma-behavior.rs:77:24
|
LL | write!(f, "{}",)?;
| ^^
-error: aborting due to 10 previous errors
+error: 1 positional argument in format string, but no arguments were given
+ --> $DIR/macro-comma-behavior.rs:81:26
+ |
+LL | writeln!(f, "{}",)?;
+ | ^^
+
+error: aborting due to 13 previous errors
let _ = column!();
}
-// compile_error! is in a companion to this test in compile-fail
+// compile_error! is in a check-fail companion to this test
#[test]
fn concat() {
($a, $b) => {
//~^ ERROR missing fragment
//~| ERROR missing fragment
+ //~| WARN this was previously accepted
()
};
}
|
LL | ($a, $b) => {
| ^^
+ |
+ = note: `#[deny(missing_fragment_specifier)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
error: aborting due to 2 previous errors
--- /dev/null
+// error-pattern: did not contain valid UTF-8
+
+fn foo() {
+ include!("not-utf8.bin")
+}
--- /dev/null
+error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8
+ --> $DIR/not-utf8.rs:4:5
+ |
+LL | include!("not-utf8.bin")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/meta-expected-error-wrong-rev.rs:13:18
+ |
+LL | let x: u32 = 22_usize;
+ | --- ^^^^^^^^ expected `u32`, found `usize`
+ | |
+ | expected due to this
+ |
+help: change the type of the numeric literal from `usize` to `u32`
+ |
+LL | let x: u32 = 22_u32;
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// ignore-compare-mode-nll
+
+// revisions: a
+// should-fail
+
+// This is a "meta-test" of the compilertest framework itself. In
+// particular, it includes the right error message, but the message
+// targets the wrong revision, so we expect the execution to fail.
+// See also `meta-expected-error-correct-rev.rs`.
+
+#[cfg(a)]
+fn foo() {
+ let x: u32 = 22_usize; //[b]~ ERROR mismatched types
+}
+
+fn main() { }
//
// build-pass
// compile-flags: -Zmir-opt-level=2 -Zvalidate-mir
-#![feature(min_const_generics)]
-
#[derive(Clone)]
struct Array<T, const N: usize>([T; N]);
--- /dev/null
+fn main() {
+ [(); & { loop { continue } } ]; //~ ERROR mismatched types
+
+ [(); loop { break }]; //~ ERROR mismatched types
+
+ [(); {while true {break}; 0}];
+ //~^ WARN denote infinite loops with
+
+ [(); { for _ in 0usize.. {}; 0}];
+ //~^ ERROR `for` is not allowed in a `const`
+ //~| ERROR calls in constants are limited to constant functions
+ //~| ERROR mutable references are not allowed in constants
+ //~| ERROR calls in constants are limited to constant functions
+}
--- /dev/null
+warning: denote infinite loops with `loop { ... }`
+ --> $DIR/issue-52443.rs:6:11
+ |
+LL | [(); {while true {break}; 0}];
+ | ^^^^^^^^^^ help: use `loop`
+ |
+ = note: `#[warn(while_true)]` on by default
+
+error[E0744]: `for` is not allowed in a `const`
+ --> $DIR/issue-52443.rs:9:12
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-52443.rs:2:10
+ |
+LL | [(); & { loop { continue } } ];
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected `usize`, found reference
+ | help: consider removing the borrow: `{ loop { continue } }`
+ |
+ = note: expected type `usize`
+ found reference `&_`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-52443.rs:4:17
+ |
+LL | [(); loop { break }];
+ | ^^^^^
+ | |
+ | expected `usize`, found `()`
+ | help: give it a value of the expected type: `break 42`
+
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-52443.rs:9:21
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^
+
+error[E0764]: mutable references are not allowed in constants
+ --> $DIR/issue-52443.rs:9:21
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-52443.rs:9:21
+ |
+LL | [(); { for _ in 0usize.. {}; 0}];
+ | ^^^^^^^^
+
+error: aborting due to 6 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0308, E0744, E0764.
+For more information about an error, try `rustc --explain E0015`.
LL | v.push(|| x = String::new());
| ^^ - borrows occur due to use of `x` in closure
| |
- | mutable borrow starts here in previous iteration of loop
+ | `x` was mutably borrowed here in the previous iteration of the loop
error[E0524]: two closures require unique access to `x` at the same time
--> $DIR/closures-in-loops.rs:20:16
| - let's call the lifetime of this reference `'1`
...
LL | result.push(&mut list[0].value);
- | ^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+ | ^^^^^^^^^^^^^^^^^^ `list[_].value` was mutably borrowed here in the previous iteration of the loop
...
LL | return result;
| ------ returning this value requires that `list[_].value` is borrowed for `'1`
LL | if let Some(n) = list[0].next.as_mut() {
| ^^^^^^^^^^^^---------
| |
- | mutable borrow starts here in previous iteration of loop
+ | `list[_].next` was mutably borrowed here in the previous iteration of the loop
| argument requires that `list[_].next` is borrowed for `'1`
error: aborting due to 2 previous errors
| -- lifetime `'a` defined here
...
LL | result.push(&mut (list.0).value);
- | ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+ | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop
...
LL | return result;
| ------ returning this value requires that `list.0.value` is borrowed for `'a`
LL | if let Some(n) = (list.0).next.as_mut() {
| ^^^^^^^^^^^^^---------
| |
- | mutable borrow starts here in previous iteration of loop
+ | `list.0.next` was mutably borrowed here in the previous iteration of the loop
| argument requires that `list.0.next` is borrowed for `'a`
error: aborting due to 2 previous errors
| -- lifetime `'a` defined here
...
LL | result.push(&mut (list.0).value);
- | ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+ | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop
...
LL | return result;
| ------ returning this value requires that `list.0.value` is borrowed for `'a`
LL | if let Some(n) = (list.0).next.as_mut() {
| ^^^^^^^^^^^^^---------
| |
- | mutable borrow starts here in previous iteration of loop
+ | `list.0.next` was mutably borrowed here in the previous iteration of the loop
| argument requires that `list.0.next` is borrowed for `'a`
error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time
| -- lifetime `'a` defined here
...
LL | result.push(&mut ((((list.0).0).0).0).0.value);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.value` was mutably borrowed here in the previous iteration of the loop
...
LL | return result;
| ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a`
LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------
| |
- | mutable borrow starts here in previous iteration of loop
+ | `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop
| argument requires that `list.0.0.0.0.0.next` is borrowed for `'a`
error: aborting due to 4 previous errors
ss.u = t;
}
-// see also compile-fail/object-lifetime-default-from-rptr-box-error.rs
+// see also ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
fn d<'a>(t: &'a Box<dyn Test+'a>, mut ss: SomeStruct<'a>) {
ss.u = t;
--- /dev/null
+// no-prefer-dynamic
+
+// This aux-file will require the eh_personality function to be codegen'd, but
+// it hasn't been defined just yet. Make sure we don't explode.
+
+#![no_std]
+#![crate_type = "rlib"]
+
+struct A;
+
+impl core::ops::Drop for A {
+ fn drop(&mut self) {}
+}
+
+pub fn foo() {
+ let _a = A;
+ panic!("wut");
+}
+
+mod std {
+ pub use core::{option, fmt};
+}
--- /dev/null
+// dont-check-compiler-stderr
+// error-pattern: `#[panic_handler]` function required, but not found
+
+#![feature(lang_items)]
+#![no_main]
+#![no_std]
+
+#[lang = "eh_personality"]
+fn eh() {}
--- /dev/null
+// dont-check-compiler-stderr
+// aux-build:some-panic-impl.rs
+
+#![feature(lang_items)]
+#![no_std]
+#![no_main]
+
+extern crate some_panic_impl;
+
+use core::panic::PanicInfo;
+
+#[panic_handler]
+fn panic(info: &PanicInfo) -> ! {
+ //~^ ERROR found duplicate lang item `panic_impl`
+ loop {}
+}
+
+#[lang = "eh_personality"]
+fn eh() {}
--- /dev/null
+// aux-build:weak-lang-items.rs
+// error-pattern: `#[panic_handler]` function required, but not found
+// error-pattern: language item required, but not found: `eh_personality`
+// ignore-emscripten compiled with panic=abort, personality not required
+
+#![no_std]
+
+extern crate core;
+extern crate weak_lang_items;
+
+fn main() {}
--- /dev/null
+error[E0259]: the name `core` is defined multiple times
+ --> $DIR/weak-lang-item.rs:8:1
+ |
+LL | extern crate core;
+ | ^^^^^^^^^^^^^^^^^^ `core` reimported here
+ |
+ = note: `core` must be defined only once in the type namespace of this module
+help: you can use `as` to change the binding name of the import
+ |
+LL | extern crate core as other_core;
+ |
+
+error: `#[panic_handler]` function required, but not found
+
+error: language item required, but not found: `eh_personality`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0259`.
--- /dev/null
+// no-prefer-dynamic
+
+#![feature(panic_runtime)]
+#![crate_type = "rlib"]
+#![panic_runtime]
+#![no_std]
+
+extern crate needs_panic_runtime;
--- /dev/null
+// no-prefer-dynamic
+
+#![feature(needs_panic_runtime)]
+#![crate_type = "rlib"]
+#![needs_panic_runtime]
+#![no_std]
--- /dev/null
+// dont-check-compiler-stderr
+// aux-build:needs-panic-runtime.rs
+// aux-build:depends.rs
+// error-pattern:cannot depend on a crate that needs a panic runtime
+
+extern crate depends;
+
+fn main() {}
--- /dev/null
+// build-fail
+// dont-check-compiler-stderr
+// error-pattern:cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
+// ignore-tidy-linelength
+// aux-build:panic-runtime-unwind.rs
+// aux-build:panic-runtime-unwind2.rs
+// aux-build:panic-runtime-lang-items.rs
+
+#![no_std]
+#![no_main]
+
+extern crate panic_runtime_unwind;
+extern crate panic_runtime_unwind2;
+extern crate panic_runtime_lang_items;
+
+fn main() {}
--- /dev/null
+// Tests that the compiler errors if the user tries to turn off unwind tables
+// when they are required.
+//
+// dont-check-compiler-stderr
+// compile-flags: -C panic=unwind -C force-unwind-tables=no
+// ignore-tidy-linelength
+//
+// error-pattern: panic=unwind requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
+
+pub fn main() {
+}
--- /dev/null
+// Tests that the compiler errors if the user tries to turn off unwind tables
+// when they are required.
+//
+// only-x86_64-windows-msvc
+// compile-flags: -C force-unwind-tables=no
+// ignore-tidy-linelength
+//
+// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
+
+pub fn main() {
+}
--- /dev/null
+// build-fail
+// dont-check-compiler-stderr
+// error-pattern:is not compiled with this crate's panic strategy `abort`
+// aux-build:panic-runtime-unwind.rs
+// compile-flags:-C panic=abort
+
+extern crate panic_runtime_unwind;
+
+fn main() {}
--- /dev/null
+// build-fail
+// dont-check-compiler-stderr
+// error-pattern:is not compiled with this crate's panic strategy `abort`
+// aux-build:panic-runtime-unwind.rs
+// aux-build:wants-panic-runtime-unwind.rs
+// compile-flags:-C panic=abort
+
+extern crate wants_panic_runtime_unwind;
+
+fn main() {}
--- /dev/null
+// run-rustfix
+// edition:2018
+
+// Regression test for issue 79694
+
+fn main() {
+ let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
+}
--- /dev/null
+// run-rustfix
+// edition:2018
+
+// Regression test for issue 79694
+
+fn main() {
+ let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
+}
--- /dev/null
+error: the order of `move` and `async` is incorrect
+ --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13
+ |
+LL | let _ = move async { };
+ | ^^^^^^^^^^
+ |
+help: try switching the order
+ |
+LL | let _ = async move { };
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
--> $DIR/issue-14303-enum.rs:1:15
|
LL | enum X<'a, T, 'b> {
- | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
error: aborting due to previous error
--> $DIR/issue-14303-fn-def.rs:1:15
|
LL | fn foo<'a, T, 'b>(x: &'a T) {}
- | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
error: aborting due to previous error
--> $DIR/issue-14303-impl.rs:3:13
|
LL | impl<'a, T, 'b> X<T> {}
- | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
error: aborting due to previous error
--> $DIR/issue-14303-struct.rs:1:17
|
LL | struct X<'a, T, 'b> {
- | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
error: aborting due to previous error
--> $DIR/issue-14303-trait.rs:1:18
|
LL | trait Foo<'a, T, 'b> {}
- | --------^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
error: aborting due to previous error
{ $+ } => { //~ ERROR expected identifier, found `+`
//~^ ERROR missing fragment specifier
$(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
- //~^ ERROR attempted to repeat an expression containing no syntax variables
}
}
LL | { $+ } => {
| ^
-error: missing fragment specifier
- --> $DIR/issue-33569.rs:2:8
- |
-LL | { $+ } => {
- | ^
-
error: expected one of: `*`, `+`, or `?`
--> $DIR/issue-33569.rs:4:13
|
LL | $(x)(y)
| ^^^
-error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
- --> $DIR/issue-33569.rs:4:10
+error: missing fragment specifier
+ --> $DIR/issue-33569.rs:2:8
|
-LL | $(x)(y)
- | ^^^
+LL | { $+ } => {
+ | ^
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
--- /dev/null
+// Regression test for #80134.
+
+fn main() {
+ (()é);
+ //~^ ERROR: expected one of `)`, `,`, `.`, `?`, or an operator
+ //~| ERROR: cannot find value `é` in this scope
+ //~| ERROR: non-ascii idents are not fully supported
+ (()æ°·);
+ //~^ ERROR: expected one of `)`, `,`, `.`, `?`, or an operator
+ //~| ERROR: cannot find value `æ°·` in this scope
+ //~| ERROR: non-ascii idents are not fully supported
+}
--- /dev/null
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `é`
+ --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8
+ |
+LL | (()é);
+ | ^
+ | |
+ | expected one of `)`, `,`, `.`, `?`, or an operator
+ | help: missing `,`
+
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `æ°·`
+ --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8
+ |
+LL | (()æ°·);
+ | -^
+ | |
+ | expected one of `)`, `,`, `.`, `?`, or an operator
+ | help: missing `,`
+
+error[E0425]: cannot find value `é` in this scope
+ --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8
+ |
+LL | (()é);
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `æ°·` in this scope
+ --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8
+ |
+LL | (()æ°·);
+ | ^^ not found in this scope
+
+error[E0658]: non-ascii idents are not fully supported
+ --> $DIR/multibyte-char-use-seperator-issue-80134.rs:4:8
+ |
+LL | (()é);
+ | ^
+ |
+ = note: see issue #55467 <https://github.com/rust-lang/rust/issues/55467> for more information
+ = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
+
+error[E0658]: non-ascii idents are not fully supported
+ --> $DIR/multibyte-char-use-seperator-issue-80134.rs:8:8
+ |
+LL | (()æ°·);
+ | ^^
+ |
+ = note: see issue #55467 <https://github.com/rust-lang/rust/issues/55467> for more information
+ = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0425, E0658.
+For more information about an error, try `rustc --explain E0425`.
impl Eq for Baz {}
const BAZ: Baz = Baz::Baz1;
-type Quux = fn(usize, usize) -> usize;
-fn quux(a: usize, b: usize) -> usize { a + b }
-const QUUX: Quux = quux;
-
fn main() {
match FOO {
FOO => {}
//~^ ERROR unreachable pattern
}
+ type Quux = fn(usize, usize) -> usize;
+ fn quux(a: usize, b: usize) -> usize { a + b }
+ const QUUX: Quux = quux;
+
match QUUX {
QUUX => {}
QUUX => {}
_ => {}
}
+
+ #[derive(PartialEq, Eq)]
+ struct Wrap<T>(T);
+ const WRAPQUUX: Wrap<Quux> = Wrap(quux);
+
+ match WRAPQUUX {
+ WRAPQUUX => {}
+ WRAPQUUX => {}
+ Wrap(_) => {}
+ }
+
+ match WRAPQUUX {
+ Wrap(_) => {}
+ WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer
+ //~^ ERROR unreachable pattern
+ }
+
+ #[derive(PartialEq, Eq)]
+ enum WhoKnows<T> {
+ Yay(T),
+ Nope,
+ };
+ const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);
+
+ match WHOKNOWSQUUX {
+ WHOKNOWSQUUX => {}
+ WhoKnows::Yay(_) => {}
+ WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer
+ //~^ ERROR unreachable pattern
+ WhoKnows::Nope => {}
+ }
}
error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:34:9
+ --> $DIR/consts-opaque.rs:30:9
|
LL | FOO => {}
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:36:9
+ --> $DIR/consts-opaque.rs:32:9
|
LL | _ => {} // should not be emitting unreachable warning
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:41:9
+ --> $DIR/consts-opaque.rs:37:9
|
LL | FOO_REF => {}
| ^^^^^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:43:9
+ --> $DIR/consts-opaque.rs:39:9
|
LL | Foo(_) => {} // should not be emitting unreachable warning
| ^^^^^^
warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:49:9
+ --> $DIR/consts-opaque.rs:45:9
|
LL | FOO_REF_REF => {}
| ^^^^^^^^^^^
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:57:9
+ --> $DIR/consts-opaque.rs:53:9
|
LL | BAR => {} // should not be emitting unreachable warning
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:57:9
+ --> $DIR/consts-opaque.rs:53:9
|
LL | Bar => {}
| --- matches any value
| ^^^ unreachable pattern
error: unreachable pattern
- --> $DIR/consts-opaque.rs:60:9
+ --> $DIR/consts-opaque.rs:56:9
|
LL | Bar => {}
| --- matches any value
| ^ unreachable pattern
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:65:9
+ --> $DIR/consts-opaque.rs:61:9
|
LL | BAR => {}
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:67:9
+ --> $DIR/consts-opaque.rs:63:9
|
LL | Bar => {} // should not be emitting unreachable warning
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:69:9
+ --> $DIR/consts-opaque.rs:65:9
|
LL | Bar => {} // should not be emitting unreachable warning
| --- matches any value
| ^ unreachable pattern
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:74:9
+ --> $DIR/consts-opaque.rs:70:9
|
LL | BAR => {}
| ^^^
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:76:9
+ --> $DIR/consts-opaque.rs:72:9
|
LL | BAR => {} // should not be emitting unreachable warning
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:76:9
+ --> $DIR/consts-opaque.rs:72:9
|
LL | BAR => {} // should not be emitting unreachable warning
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:79:9
+ --> $DIR/consts-opaque.rs:75:9
|
LL | _ => {} // should not be emitting unreachable warning
| ^
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:84:9
+ --> $DIR/consts-opaque.rs:80:9
|
LL | BAZ => {}
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:86:9
+ --> $DIR/consts-opaque.rs:82:9
|
LL | Baz::Baz1 => {} // should not be emitting unreachable warning
| ^^^^^^^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:88:9
+ --> $DIR/consts-opaque.rs:84:9
|
LL | _ => {}
| ^
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:94:9
+ --> $DIR/consts-opaque.rs:90:9
|
LL | BAZ => {}
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:96:9
+ --> $DIR/consts-opaque.rs:92:9
|
LL | _ => {}
| ^
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
- --> $DIR/consts-opaque.rs:101:9
+ --> $DIR/consts-opaque.rs:97:9
|
LL | BAZ => {}
| ^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:103:9
+ --> $DIR/consts-opaque.rs:99:9
|
LL | Baz::Baz2 => {} // should not be emitting unreachable warning
| ^^^^^^^^^
error: unreachable pattern
- --> $DIR/consts-opaque.rs:105:9
+ --> $DIR/consts-opaque.rs:101:9
|
LL | _ => {} // should not be emitting unreachable warning
| ^
-error: aborting due to 22 previous errors; 1 warning emitted
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:127:9
+ |
+LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer
+ | ^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/consts-opaque.rs:141:9
+ |
+LL | WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer
+ | ^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors; 1 warning emitted
#![feature(exclusive_range_pattern)]
#![feature(assoc_char_consts)]
+#![allow(overlapping_range_endpoints)]
#![deny(unreachable_patterns)]
macro_rules! m {
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
- --> $DIR/exhaustiveness.rs:47:8
+ --> $DIR/exhaustiveness.rs:48:8
|
LL | m!(0u8, 0..255);
| ^^^ pattern `u8::MAX` not covered
= note: the matched value is of type `u8`
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
- --> $DIR/exhaustiveness.rs:48:8
+ --> $DIR/exhaustiveness.rs:49:8
|
LL | m!(0u8, 0..=254);
| ^^^ pattern `u8::MAX` not covered
= note: the matched value is of type `u8`
error[E0004]: non-exhaustive patterns: `0_u8` not covered
- --> $DIR/exhaustiveness.rs:49:8
+ --> $DIR/exhaustiveness.rs:50:8
|
LL | m!(0u8, 1..=255);
| ^^^ pattern `0_u8` not covered
= note: the matched value is of type `u8`
error[E0004]: non-exhaustive patterns: `42_u8` not covered
- --> $DIR/exhaustiveness.rs:50:8
+ --> $DIR/exhaustiveness.rs:51:8
|
LL | m!(0u8, 0..42 | 43..=255);
| ^^^ pattern `42_u8` not covered
= note: the matched value is of type `u8`
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
- --> $DIR/exhaustiveness.rs:51:8
+ --> $DIR/exhaustiveness.rs:52:8
|
LL | m!(0i8, -128..127);
| ^^^ pattern `i8::MAX` not covered
= note: the matched value is of type `i8`
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
- --> $DIR/exhaustiveness.rs:52:8
+ --> $DIR/exhaustiveness.rs:53:8
|
LL | m!(0i8, -128..=126);
| ^^^ pattern `i8::MAX` not covered
= note: the matched value is of type `i8`
error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
- --> $DIR/exhaustiveness.rs:53:8
+ --> $DIR/exhaustiveness.rs:54:8
|
LL | m!(0i8, -127..=127);
| ^^^ pattern `i8::MIN` not covered
= note: the matched value is of type `i8`
error[E0004]: non-exhaustive patterns: `0_i8` not covered
- --> $DIR/exhaustiveness.rs:54:11
+ --> $DIR/exhaustiveness.rs:55:11
|
LL | match 0i8 {
| ^^^ pattern `0_i8` not covered
= note: the matched value is of type `i8`
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
- --> $DIR/exhaustiveness.rs:59:8
+ --> $DIR/exhaustiveness.rs:60:8
|
LL | m!(0u128, 0..=ALMOST_MAX);
| ^^^^^ pattern `u128::MAX` not covered
= note: the matched value is of type `u128`
error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
- --> $DIR/exhaustiveness.rs:60:8
+ --> $DIR/exhaustiveness.rs:61:8
|
LL | m!(0u128, 0..=4);
| ^^^^^ pattern `5_u128..=u128::MAX` not covered
= note: the matched value is of type `u128`
error[E0004]: non-exhaustive patterns: `0_u128` not covered
- --> $DIR/exhaustiveness.rs:61:8
+ --> $DIR/exhaustiveness.rs:62:8
|
LL | m!(0u128, 1..=u128::MAX);
| ^^^^^ pattern `0_u128` not covered
= note: the matched value is of type `u128`
error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
- --> $DIR/exhaustiveness.rs:69:11
+ --> $DIR/exhaustiveness.rs:70:11
|
LL | match (0u8, true) {
| ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
#![feature(exclusive_range_pattern)]
-#![deny(overlapping_patterns)]
+#![deny(overlapping_range_endpoints)]
macro_rules! m {
($s:expr, $t1:pat, $t2:pat) => {
}
fn main() {
- m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns covering the same range
- m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns covering the same range
+ m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns overlap on their endpoints
+ m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns overlap on their endpoints
m!(0u8, 20..=30, 31..=40);
m!(0u8, 20..=30, 29..=40);
- m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns covering the same range
+ m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints
m!(0u8, 20.. 30, 28..=40);
m!(0u8, 20.. 30, 30..=40);
m!(0u8, 20..=30, 30..=30);
- m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns covering the same range
+ m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns overlap on their endpoints
m!(0u8, 20..=30, 29..=30);
m!(0u8, 20..=30, 20..=20);
m!(0u8, 20..=30, 20..=21);
- m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns covering the same range
+ m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns overlap on their endpoints
m!(0u8, 20..=30, 20);
m!(0u8, 20..=30, 25);
m!(0u8, 20..=30, 30);
m!(0u8, 20.. 30, 29);
- m!(0u8, 20, 20..=30); //~ ERROR multiple patterns covering the same range
+ m!(0u8, 20, 20..=30);
m!(0u8, 25, 20..=30);
- m!(0u8, 30, 20..=30); //~ ERROR multiple patterns covering the same range
+ m!(0u8, 30, 20..=30);
+ match 0u8 {
+ 0..=10 => {}
+ 20..=30 => {}
+ 10..=20 => {} //~ ERROR multiple patterns overlap on their endpoints
+ _ => {}
+ }
match (0u8, true) {
(0..=10, true) => {}
(10..20, true) => {} // not detected
}
match (true, 0u8) {
(true, 0..=10) => {}
- (true, 10..20) => {} //~ ERROR multiple patterns covering the same range
+ (true, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints
(false, 10..20) => {}
_ => {}
}
match Some(0u8) {
Some(0..=10) => {}
- Some(10..20) => {} //~ ERROR multiple patterns covering the same range
+ Some(10..20) => {} //~ ERROR multiple patterns overlap on their endpoints
_ => {}
}
}
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
--> $DIR/overlapping_range_endpoints.rs:15:22
|
LL | m!(0u8, 20..=30, 30..=40);
- | ------- ^^^^^^^ overlapping patterns
+ | ------- ^^^^^^^ ... with this range
| |
- | this range overlaps on `30_u8`
+ | this range overlaps on `30_u8`...
|
note: the lint level is defined here
--> $DIR/overlapping_range_endpoints.rs:2:9
|
-LL | #![deny(overlapping_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(overlapping_range_endpoints)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: you likely meant to write mutually exclusive ranges
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
--> $DIR/overlapping_range_endpoints.rs:16:22
|
LL | m!(0u8, 30..=40, 20..=30);
- | ------- ^^^^^^^ overlapping patterns
+ | ------- ^^^^^^^ ... with this range
| |
- | this range overlaps on `30_u8`
+ | this range overlaps on `30_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
--> $DIR/overlapping_range_endpoints.rs:19:22
|
LL | m!(0u8, 20.. 30, 29..=40);
- | ------- ^^^^^^^ overlapping patterns
+ | ------- ^^^^^^^ ... with this range
| |
- | this range overlaps on `29_u8`
+ | this range overlaps on `29_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
--> $DIR/overlapping_range_endpoints.rs:23:22
|
LL | m!(0u8, 20..=30, 30..=31);
- | ------- ^^^^^^^ overlapping patterns
+ | ------- ^^^^^^^ ... with this range
| |
- | this range overlaps on `30_u8`
+ | this range overlaps on `30_u8`...
+ |
+ = note: you likely meant to write mutually exclusive ranges
-error: multiple patterns covering the same range
+error: multiple patterns overlap on their endpoints
--> $DIR/overlapping_range_endpoints.rs:27:22
|
LL | m!(0u8, 20..=30, 19..=20);
- | ------- ^^^^^^^ overlapping patterns
+ | ------- ^^^^^^^ ... with this range
| |
- | this range overlaps on `20_u8`
-
-error: multiple patterns covering the same range
- --> $DIR/overlapping_range_endpoints.rs:32:17
+ | this range overlaps on `20_u8`...
|
-LL | m!(0u8, 20, 20..=30);
- | -- ^^^^^^^ overlapping patterns
- | |
- | this range overlaps on `20_u8`
+ = note: you likely meant to write mutually exclusive ranges
-error: multiple patterns covering the same range
- --> $DIR/overlapping_range_endpoints.rs:34:17
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:39:9
|
-LL | m!(0u8, 30, 20..=30);
- | -- ^^^^^^^ overlapping patterns
- | |
- | this range overlaps on `30_u8`
+LL | 0..=10 => {}
+ | ------ this range overlaps on `10_u8`...
+LL | 20..=30 => {}
+ | ------- this range overlaps on `20_u8`...
+LL | 10..=20 => {}
+ | ^^^^^^^ ... with this range
+ |
+ = note: you likely meant to write mutually exclusive ranges
-error: multiple patterns covering the same range
- --> $DIR/overlapping_range_endpoints.rs:44:16
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:50:16
|
LL | (true, 0..=10) => {}
- | ------ this range overlaps on `10_u8`
+ | ------ this range overlaps on `10_u8`...
LL | (true, 10..20) => {}
- | ^^^^^^ overlapping patterns
+ | ^^^^^^ ... with this range
+ |
+ = note: you likely meant to write mutually exclusive ranges
-error: multiple patterns covering the same range
- --> $DIR/overlapping_range_endpoints.rs:50:14
+error: multiple patterns overlap on their endpoints
+ --> $DIR/overlapping_range_endpoints.rs:56:14
|
LL | Some(0..=10) => {}
- | ------ this range overlaps on `10_u8`
+ | ------ this range overlaps on `10_u8`...
LL | Some(10..20) => {}
- | ^^^^^^ overlapping patterns
+ | ^^^^^^ ... with this range
+ |
+ = note: you likely meant to write mutually exclusive ranges
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
#![feature(exclusive_range_pattern)]
+#![allow(overlapping_range_endpoints)]
#![deny(unreachable_patterns)]
macro_rules! m {
error: unreachable pattern
- --> $DIR/reachability.rs:16:17
+ --> $DIR/reachability.rs:17:17
|
LL | m!(0u8, 42, 42);
| ^^
|
note: the lint level is defined here
- --> $DIR/reachability.rs:2:9
+ --> $DIR/reachability.rs:3:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:20:22
+ --> $DIR/reachability.rs:21:22
|
LL | m!(0u8, 20..=30, 20);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:21:22
+ --> $DIR/reachability.rs:22:22
|
LL | m!(0u8, 20..=30, 21);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:22:22
+ --> $DIR/reachability.rs:23:22
|
LL | m!(0u8, 20..=30, 25);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:23:22
+ --> $DIR/reachability.rs:24:22
|
LL | m!(0u8, 20..=30, 29);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:24:22
+ --> $DIR/reachability.rs:25:22
|
LL | m!(0u8, 20..=30, 30);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:27:21
+ --> $DIR/reachability.rs:28:21
|
LL | m!(0u8, 20..30, 20);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:28:21
+ --> $DIR/reachability.rs:29:21
|
LL | m!(0u8, 20..30, 21);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:29:21
+ --> $DIR/reachability.rs:30:21
|
LL | m!(0u8, 20..30, 25);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:30:21
+ --> $DIR/reachability.rs:31:21
|
LL | m!(0u8, 20..30, 29);
| ^^
error: unreachable pattern
- --> $DIR/reachability.rs:34:22
+ --> $DIR/reachability.rs:35:22
|
LL | m!(0u8, 20..=30, 20..=30);
| ^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:35:22
+ --> $DIR/reachability.rs:36:22
|
LL | m!(0u8, 20.. 30, 20.. 30);
| ^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:36:22
+ --> $DIR/reachability.rs:37:22
|
LL | m!(0u8, 20..=30, 20.. 30);
| ^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:38:22
+ --> $DIR/reachability.rs:39:22
|
LL | m!(0u8, 20..=30, 21..=30);
| ^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:39:22
+ --> $DIR/reachability.rs:40:22
|
LL | m!(0u8, 20..=30, 20..=29);
| ^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:41:24
+ --> $DIR/reachability.rs:42:24
|
LL | m!('a', 'A'..='z', 'a'..='z');
| ^^^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:48:9
+ --> $DIR/reachability.rs:49:9
|
LL | 5..=8 => {},
| ^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:54:9
+ --> $DIR/reachability.rs:55:9
|
LL | 5..15 => {},
| ^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:61:9
+ --> $DIR/reachability.rs:62:9
|
LL | 5..25 => {},
| ^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:69:9
+ --> $DIR/reachability.rs:70:9
|
LL | 5..25 => {},
| ^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:75:9
+ --> $DIR/reachability.rs:76:9
|
LL | 5..15 => {},
| ^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:82:9
+ --> $DIR/reachability.rs:83:9
|
LL | '\u{D7FF}'..='\u{E000}' => {},
| ^^^^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:103:9
+ --> $DIR/reachability.rs:104:9
|
LL | &FOO => {}
| ^^^^
error: unreachable pattern
- --> $DIR/reachability.rs:104:9
+ --> $DIR/reachability.rs:105:9
|
LL | BAR => {}
| ^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: item has unused generic parameters
--> $DIR/closures.rs:19:19
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: item has unused generic parameters
--> $DIR/functions.rs:15:8
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: item has unused generic parameters
--> $DIR/generators.rs:36:5
--- /dev/null
+#![feature(crate_visibility_modifier)]
+
+mod rank {
+ pub use self::Professor::*;
+ //~^ ERROR enum is private and its variants cannot be re-exported
+ pub use self::Lieutenant::{JuniorGrade, Full};
+ //~^ ERROR variant `JuniorGrade` is private and cannot be re-exported
+ //~| ERROR variant `Full` is private and cannot be re-exported
+ pub use self::PettyOfficer::*;
+ //~^ ERROR enum is private and its variants cannot be re-exported
+ pub use self::Crewman::*;
+ //~^ ERROR enum is private and its variants cannot be re-exported
+
+ enum Professor {
+ Adjunct,
+ Assistant,
+ Associate,
+ Full
+ }
+
+ enum Lieutenant {
+ JuniorGrade,
+ Full,
+ }
+
+ pub(in rank) enum PettyOfficer {
+ SecondClass,
+ FirstClass,
+ Chief,
+ MasterChief
+ }
+
+ crate enum Crewman {
+ Recruit,
+ Apprentice,
+ Full
+ }
+
+}
+
+fn main() {}
--- /dev/null
+error: variant `JuniorGrade` is private and cannot be re-exported
+ --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32
+ |
+LL | pub use self::Lieutenant::{JuniorGrade, Full};
+ | ^^^^^^^^^^^
+...
+LL | enum Lieutenant {
+ | --------------- help: consider making the enum public: `pub enum Lieutenant`
+
+error: variant `Full` is private and cannot be re-exported
+ --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:45
+ |
+LL | pub use self::Lieutenant::{JuniorGrade, Full};
+ | ^^^^
+
+error: enum is private and its variants cannot be re-exported
+ --> $DIR/issue-46209-private-enum-variant-reexport.rs:4:13
+ |
+LL | pub use self::Professor::*;
+ | ^^^^^^^^^^^^^^^^^^
+...
+LL | enum Professor {
+ | -------------- help: consider making the enum public: `pub enum Professor`
+
+error: enum is private and its variants cannot be re-exported
+ --> $DIR/issue-46209-private-enum-variant-reexport.rs:9:13
+ |
+LL | pub use self::PettyOfficer::*;
+ | ^^^^^^^^^^^^^^^^^^^^^
+...
+LL | pub(in rank) enum PettyOfficer {
+ | ------------------------------ help: consider making the enum public: `pub enum PettyOfficer`
+
+error: enum is private and its variants cannot be re-exported
+ --> $DIR/issue-46209-private-enum-variant-reexport.rs:11:13
+ |
+LL | pub use self::Crewman::*;
+ | ^^^^^^^^^^^^^^^^
+...
+LL | crate enum Crewman {
+ | ------------------ help: consider making the enum public: `pub enum Crewman`
+
+error: aborting due to 5 previous errors
+
let m : Box<dyn Trait> = make_val();
// assert_eq!(object_invoke1(&*m), (4,5));
// ~~~~~~~~~~~~~~~~~~~
- // this call yields a compilation error; see compile-fail/dropck-object-cycle.rs
+ // this call yields a compilation error; see ui/span/dropck-object-cycle.rs
// for details.
assert_eq!(object_invoke2(&*m), 5);
// Test that a type which is contravariant with respect to its region
// parameter compiles successfully when used in a contravariant way.
//
-// Note: see compile-fail/variance-regions-*.rs for the tests that check that the
+// Note: see ui/variance/variance-regions-*.rs for the tests that check that the
// variance inference works in the first place.
// pretty-expanded FIXME #23616
// Test that a type which is covariant with respect to its region
// parameter is successful when used in a covariant way.
//
-// Note: see compile-fail/variance-regions-*.rs for the tests that
+// Note: see ui/variance/variance-regions-*.rs for the tests that
// check that the variance inference works in the first place.
// This is covariant with respect to 'a, meaning that
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
error: aborting due to 5 previous errors; 1 warning emitted
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/disallowed-positions.rs:22:12
// pretty-expanded FIXME #23616
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
#[repr(simd)]
#[derive(Copy, Clone)]
// run-pass
#![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
use std::ops;
// ignore-emscripten
#![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
// ignore-emscripten FIXME(#45351) hits an LLVM assert
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
#[repr(simd)]
#[derive(Copy, Clone)]
+++ /dev/null
-// run-rustfix
-
-#![allow(unused_imports)]
-
-pub mod x {
- pub struct A;
- pub struct B;
-}
-
-// `.` is similar to `,` so list parsing should continue to closing `}`
-use x::{A, B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.`
-
-fn main() {}
-// run-rustfix
-
#![allow(unused_imports)]
pub mod x {
error: expected one of `,`, `::`, `as`, or `}`, found `.`
- --> $DIR/similar-tokens.rs:11:10
+ --> $DIR/similar-tokens.rs:9:10
|
LL | use x::{A. B};
| ^
// Reject mixing cyclic structure and Drop when using fixed length
// arrays.
//
-// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+// (Compare against ui/span/dropck_vec_cycle_checked.rs)
// Reject mixing cyclic structure and Drop when using Vec.
//
-// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
+// (Compare against ui/span/dropck_arr_cycle_checked.rs)
use std::cell::Cell;
use id::Id;
#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Make sure we *can* project non-defaulted associated types
-// cf compile-fail/specialization-default-projection.rs
+// cf ui/specialization/specialization-default-projection.rs
// First, do so without any use of specialization
--- /dev/null
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
+pub trait Foo {
+ fn foo();
+}
+
+impl Foo for i32 {}
+impl Foo for i64 {
+ fn foo() {}
+ //~^ERROR `foo` specializes an item from a parent `impl`
+}
+impl<T> Foo for T {
+ fn foo() {}
+}
+
+fn main() {
+ i32::foo();
+ i64::foo();
+ u8::foo();
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-50452-fail.rs:1:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+ = help: consider using `min_specialization` instead, which is more stable and complete
+
+error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
+ --> $DIR/issue-50452-fail.rs:10:5
+ |
+LL | fn foo() {}
+ | ^^^^^^^^^^^ cannot specialize default item `foo`
+...
+LL | / impl<T> Foo for T {
+LL | | fn foo() {}
+LL | | }
+ | |_- parent `impl` is here
+ |
+ = note: to specialize, `foo` in the parent `impl` must be marked `default`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0520`.
#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Make sure we *can* project non-defaulted associated types
-// cf compile-fail/specialization-default-projection.rs
+// cf ui/specialization/specialization-default-projection.rs
// First, do so without any use of specialization
// Issue 23030: Workaround overflowing discriminant
// with explicit assignments.
-// See also compile-fail/overflow-discrim.rs, which shows what
+// See also ui/discrim/discrim-overflow.rs, which shows what
// happens if you leave the OhNo explicit cases out here.
fn f_i8() {
ss.u = t;
}
-// see also compile-fail/object-lifetime-default-from-rptr-box-error.rs
+// see also ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
fn d<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
ss.u = t;
--> $DIR/suggest-move-lifetimes.rs:1:13
|
LL | struct A<T, 'a> {
- | ----^^- help: reorder the parameters: lifetimes, then types: `<'a, T>`
+ | ----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/suggest-move-lifetimes.rs:5:13
|
LL | struct B<T, 'a, U> {
- | ----^^---- help: reorder the parameters: lifetimes, then types: `<'a, T, U>`
+ | ----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/suggest-move-lifetimes.rs:10:16
|
LL | struct C<T, U, 'a> {
- | -------^^- help: reorder the parameters: lifetimes, then types: `<'a, T, U>`
+ | -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/suggest-move-lifetimes.rs:15:16
|
LL | struct D<T, U, 'a, 'b, V, 'c> {
- | -------^^--^^-----^^- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
+ | -------^^--^^-----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>`
error: aborting due to 4 previous errors
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
//! change from `use foo::TraitB` to use `foo::TraitB` in the hash
//! (SVH) computation (#14132), since that will affect method
//! resolution.
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
//! change from `use foo::TraitB` to use `foo::TraitB` in the hash
//! (SVH) computation (#14132), since that will affect method
//! resolution.
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
//! change from `use foo::TraitB` to use `foo::TraitB` in the hash
//! (SVH) computation (#14132), since that will affect method
//! resolution.
// aux-build:svh-uta-change-use-trait.rs
// normalize-stderr-test: "(crate `(\w+)`:) .*" -> "$1 $$PATH_$2"
-//! "compile-fail/svh-uta-trait.rs" is checking that we detect a
+//! "svh-uta-trait.rs" is checking that we detect a
//! change from `use foo::TraitB` to use `foo::TraitB` in the hash
//! (SVH) computation (#14132), since that will affect method
//! resolution.
// build-fail
// compile-flags: -Z symbol-mangling-version=v0
-
-#![feature(min_const_generics, rustc_attrs)]
+#![feature(rustc_attrs)]
pub struct Unsigned<const F: u8>;
error: symbol-name(_RMCs4fqI2P2rA04_25const_generics_demanglingINtB0_8UnsignedKhb_E)
- --> $DIR/const-generics-demangling.rs:8:1
+ --> $DIR/const-generics-demangling.rs:7:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(<const_generics_demangling[317d481089b8c8fe]::Unsigned<11: u8>>)
- --> $DIR/const-generics-demangling.rs:8:1
+ --> $DIR/const-generics-demangling.rs:7:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<const_generics_demangling::Unsigned<11>>)
- --> $DIR/const-generics-demangling.rs:8:1
+ --> $DIR/const-generics-demangling.rs:7:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: symbol-name(_RMs_Cs4fqI2P2rA04_25const_generics_demanglingINtB2_6SignedKsn98_E)
- --> $DIR/const-generics-demangling.rs:16:1
+ --> $DIR/const-generics-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(<const_generics_demangling[317d481089b8c8fe]::Signed<-152: i16>>)
- --> $DIR/const-generics-demangling.rs:16:1
+ --> $DIR/const-generics-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<const_generics_demangling::Signed<-152>>)
- --> $DIR/const-generics-demangling.rs:16:1
+ --> $DIR/const-generics-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: symbol-name(_RMs0_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4BoolKb1_E)
- --> $DIR/const-generics-demangling.rs:24:1
+ --> $DIR/const-generics-demangling.rs:23:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(<const_generics_demangling[317d481089b8c8fe]::Bool<true: bool>>)
- --> $DIR/const-generics-demangling.rs:24:1
+ --> $DIR/const-generics-demangling.rs:23:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<const_generics_demangling::Bool<true>>)
- --> $DIR/const-generics-demangling.rs:24:1
+ --> $DIR/const-generics-demangling.rs:23:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: symbol-name(_RMs1_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4CharKc2202_E)
- --> $DIR/const-generics-demangling.rs:32:1
+ --> $DIR/const-generics-demangling.rs:31:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(<const_generics_demangling[317d481089b8c8fe]::Char<'∂': char>>)
- --> $DIR/const-generics-demangling.rs:32:1
+ --> $DIR/const-generics-demangling.rs:31:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<const_generics_demangling::Char<'∂'>>)
- --> $DIR/const-generics-demangling.rs:32:1
+ --> $DIR/const-generics-demangling.rs:31:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
// check-pass
// revisions: legacy v0
//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
- //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
- #![feature(min_const_generics)]
+// `char`
+pub struct Char<const F: char>;
- // `char`
- pub struct Char<const F: char>;
+impl Char<'A'> {
+ pub fn foo() {}
+}
- impl Char<'A'> {
- pub fn foo() {}
- }
+impl<const F: char> Char<F> {
+ pub fn bar() {}
+}
- impl<const F: char> Char<F> {
- pub fn bar() {}
- }
+// `i8`
+pub struct I8<const F: i8>;
- // `i8`
- pub struct I8<const F: i8>;
+impl I8<{i8::MIN}> {
+ pub fn foo() {}
+}
- impl I8<{i8::MIN}> {
- pub fn foo() {}
- }
+impl I8<{i8::MAX}> {
+ pub fn foo() {}
+}
- impl I8<{i8::MAX}> {
- pub fn foo() {}
- }
+impl<const F: i8> I8<F> {
+ pub fn bar() {}
+}
- impl<const F: i8> I8<F> {
- pub fn bar() {}
- }
+// `i16`
+pub struct I16<const F: i16>;
- // `i16`
- pub struct I16<const F: i16>;
+impl I16<{i16::MIN}> {
+ pub fn foo() {}
+}
- impl I16<{i16::MIN}> {
- pub fn foo() {}
- }
+impl<const F: i16> I16<F> {
+ pub fn bar() {}
+}
- impl<const F: i16> I16<F> {
- pub fn bar() {}
- }
+// `i32`
+pub struct I32<const F: i32>;
- // `i32`
- pub struct I32<const F: i32>;
+impl I32<{i32::MIN}> {
+ pub fn foo() {}
+}
- impl I32<{i32::MIN}> {
- pub fn foo() {}
- }
+impl<const F: i32> I32<F> {
+ pub fn bar() {}
+}
- impl<const F: i32> I32<F> {
- pub fn bar() {}
- }
+// `i64`
+pub struct I64<const F: i64>;
- // `i64`
- pub struct I64<const F: i64>;
+impl I64<{i64::MIN}> {
+ pub fn foo() {}
+}
- impl I64<{i64::MIN}> {
- pub fn foo() {}
- }
+impl<const F: i64> I64<F> {
+ pub fn bar() {}
+}
- impl<const F: i64> I64<F> {
- pub fn bar() {}
- }
+// `i128`
+pub struct I128<const F: i128>;
- // `i128`
- pub struct I128<const F: i128>;
+impl I128<{i128::MIN}> {
+ pub fn foo() {}
+}
- impl I128<{i128::MIN}> {
- pub fn foo() {}
- }
+impl<const F: i128> I128<F> {
+ pub fn bar() {}
+}
- impl<const F: i128> I128<F> {
- pub fn bar() {}
- }
+// `isize`
+pub struct ISize<const F: isize>;
- // `isize`
- pub struct ISize<const F: isize>;
+impl ISize<3> {
+ pub fn foo() {}
+}
- impl ISize<3> {
- pub fn foo() {}
- }
-
- impl<const F: isize> ISize<F> {
- pub fn bar() {}
- }
+impl<const F: isize> ISize<F> {
+ pub fn bar() {}
+}
// check-pass
// revisions: legacy v0
//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
- //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
-#![feature(min_const_generics)]
pub struct Bar<const F: bool>;
--- /dev/null
+// dont-check-compiler-stderr
+
+#![feature(cfg_target_thread_local, thread_local_internals)]
+
+// On platforms *without* `#[thread_local]`, use
+// a custom non-`Sync` type to fake the same error.
+#[cfg(not(target_thread_local))]
+struct Key<T> {
+ _data: std::cell::UnsafeCell<Option<T>>,
+ _flag: std::cell::Cell<()>,
+}
+
+#[cfg(not(target_thread_local))]
+impl<T> Key<T> {
+ const fn new() -> Self {
+ Key {
+ _data: std::cell::UnsafeCell::new(None),
+ _flag: std::cell::Cell::new(()),
+ }
+ }
+}
+
+#[cfg(target_thread_local)]
+use std::thread::__FastLocalKeyInner as Key;
+
+static __KEY: Key<()> = Key::new();
+//~^ ERROR `UnsafeCell<Option<()>>` cannot be shared between threads
+//~| ERROR cannot be shared between threads safely [E0277]
+
+fn main() {}
--- /dev/null
+#![feature(const_fn)]
+#![feature(thread_local)]
+#![feature(cfg_target_thread_local, thread_local_internals)]
+
+type Foo = std::cell::RefCell<String>;
+
+#[cfg(target_thread_local)]
+#[thread_local]
+static __KEY: std::thread::__FastLocalKeyInner<Foo> =
+ std::thread::__FastLocalKeyInner::new();
+
+#[cfg(not(target_thread_local))]
+static __KEY: std::thread::__OsLocalKeyInner<Foo> =
+ std::thread::__OsLocalKeyInner::new();
+
+fn __getit() -> std::option::Option<&'static Foo>
+{
+ __KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
+}
+
+static FOO: std::thread::LocalKey<Foo> =
+ std::thread::LocalKey::new(__getit);
+//~^ ERROR call to unsafe function is unsafe
+
+fn main() {
+ FOO.with(|foo| println!("{}", foo.borrow()));
+ std::thread::spawn(|| {
+ FOO.with(|foo| *foo.borrow_mut() += "foo");
+ }).join().unwrap();
+ FOO.with(|foo| println!("{}", foo.borrow()));
+}
--- /dev/null
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:18:5
+ |
+LL | __KEY.get(Default::default)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:22:5
+ |
+LL | std::thread::LocalKey::new(__getit);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
// Test a case of a trait which extends the same supertrait twice, but
// with difference type parameters. Test that we can invoke the
// various methods in various ways successfully.
-// See also `compile-fail/trait-repeated-supertrait-ambig.rs`.
+// See also `ui/traits/trait-repeated-supertrait-ambig.rs`.
trait CompareTo<T> {
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: consider using `min_const_generics` instead, which is more stable and complete
warning: 1 warning emitted
#![allow(dead_code)]
//
-// See also: compile-fail/unsafe-fn-called-from-safe.rs
+// See also: ui/unsafe/unsafe-fn-called-from-safe.rs
// pretty-expanded FIXME #23616
#![allow(dead_code)]
//
-// See also: compile-fail/unsafe-fn-called-from-safe.rs
+// See also: ui/unsafe/unsafe-fn-called-from-safe.rs
// pretty-expanded FIXME #23616
let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets);
package("rustc", HOSTS);
package("rustc-dev", HOSTS);
+ package("reproducible-artifacts", HOSTS);
package("rustc-docs", HOSTS);
package("cargo", HOSTS);
package("rust-mingw", MINGW);
-Subproject commit a3c2627fbc2f5391c65ba45ab53b81bf71fa323c
+Subproject commit 75d5d8cffe3464631f82dcd3c470b78dc1dda8bb
[[bin]]
name = "cargo-clippy"
+test = false
path = "src/main.rs"
[[bin]]
```terminal
cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
```
+Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`.
### Specifying the minimum supported Rust version
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
- if lifetime.name.ident().name != kw::Invalid && lifetime.name.ident().name != kw::StaticLifetime {
+ if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime {
self.lifetimes_used_in_body = true;
}
}
#![feature(rustc_private)]
#![feature(once_cell)]
-#![feature(bool_to_option)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]
use std::borrow::Cow;
use std::env;
-use std::iter;
use std::lazy::SyncLazy;
use std::ops::Deref;
use std::panic;
None
}
+#[test]
+fn test_arg_value() {
+ let args = &["--bar=bar", "--foobar", "123", "--foo"];
+
+ assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
+ assert_eq!(arg_value(args, "--bar", |_| false), None);
+ assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
+ assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
+ assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
+ assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
+ assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
+ assert_eq!(arg_value(args, "--foo", |_| true), None);
+}
+
struct DefaultCallbacks;
impl rustc_driver::Callbacks for DefaultCallbacks {}
})
}
-fn remove_clippy_args<'a, T, U, I>(args: &mut Vec<T>, clippy_args: I)
-where
- T: AsRef<str>,
- U: AsRef<str> + ?Sized + 'a,
- I: Iterator<Item = &'a U> + Clone,
-{
- let args_iter = clippy_args.map(AsRef::as_ref);
- let args_count = args_iter.clone().count();
-
- if args_count > 0 {
- if let Some(start) = args.windows(args_count).enumerate().find_map(|(current, window)| {
- window
- .iter()
- .map(AsRef::as_ref)
- .eq(args_iter.clone())
- .then_some(current)
- }) {
- args.drain(start..start + args_count);
- }
- }
-}
-
#[allow(clippy::too_many_lines)]
pub fn main() {
rustc_driver::init_rustc_env_logger();
args.extend(vec!["--sysroot".into(), sys_root]);
};
- let clippy_args = env::var("CLIPPY_ARGS").unwrap_or_default();
- let clippy_args = clippy_args.split_whitespace();
- let no_deps = clippy_args.clone().any(|flag| flag == "--no-deps");
+ let mut no_deps = false;
+ let clippy_args = env::var("CLIPPY_ARGS")
+ .unwrap_or_default()
+ .split("__CLIPPY_HACKERY__")
+ .filter_map(|s| match s {
+ "" => None,
+ "--no-deps" => {
+ no_deps = true;
+ None
+ },
+ _ => Some(s.to_string()),
+ })
+ .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()])
+ .collect::<Vec<String>>();
// We enable Clippy if one of the following conditions is met
// - IF Clippy is run on its test suite OR
let clippy_enabled = clippy_tests_set || (!cap_lints_allow && (!no_deps || in_primary_package));
if clippy_enabled {
- remove_clippy_args(&mut args, iter::once("--no-deps"));
- args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
- } else {
- // Remove all flags passed through RUSTFLAGS if Clippy is not enabled.
- remove_clippy_args(&mut args, clippy_args);
+ args.extend(clippy_args);
}
let mut clippy = ClippyCallbacks;
rustc_driver::RunCompiler::new(&args, callbacks).run()
}))
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_arg_value() {
- let args = &["--bar=bar", "--foobar", "123", "--foo"];
-
- assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
- assert_eq!(arg_value(args, "--bar", |_| false), None);
- assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
- assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
- assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
- assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
- assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
- assert_eq!(arg_value(args, "--foo", |_| true), None);
- }
-
- #[test]
- fn removes_clippy_args_from_start() {
- let mut args = vec!["-D", "clippy::await_holding_lock", "--cfg", r#"feature="some_feat""#];
- let clippy_args = ["-D", "clippy::await_holding_lock"].iter();
-
- remove_clippy_args(&mut args, clippy_args);
- assert_eq!(args, &["--cfg", r#"feature="some_feat""#]);
- }
-
- #[test]
- fn removes_clippy_args_from_end() {
- let mut args = vec!["-Zui-testing", "-A", "clippy::empty_loop", "--no-deps"];
- let clippy_args = ["-A", "clippy::empty_loop", "--no-deps"].iter();
-
- remove_clippy_args(&mut args, clippy_args);
- assert_eq!(args, &["-Zui-testing"]);
- }
-
- #[test]
- fn removes_clippy_args_from_middle() {
- let mut args = vec!["-Zui-testing", "-W", "clippy::filter_map", "-L", "serde"];
- let clippy_args = ["-W", "clippy::filter_map"].iter();
-
- remove_clippy_args(&mut args, clippy_args);
- assert_eq!(args, &["-Zui-testing", "-L", "serde"]);
- }
-
- #[test]
- fn no_clippy_args_to_remove() {
- let mut args = vec!["-Zui-testing", "-L", "serde"];
- let clippy_args: [&str; 0] = [];
-
- remove_clippy_args(&mut args, clippy_args.iter());
- assert_eq!(args, &["-Zui-testing", "-L", "serde"]);
- }
-}
-#![feature(bool_to_option)]
-#![feature(command_access)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]
unstable_options: bool,
cargo_subcommand: &'static str,
args: Vec<String>,
- clippy_args: Option<String>,
+ clippy_args: Vec<String>,
}
impl ClippyCmd {
args.insert(0, "+nightly".to_string());
}
- let mut clippy_args = old_args.collect::<Vec<String>>().join(" ");
- if cargo_subcommand == "fix" && !clippy_args.contains("--no-deps") {
- clippy_args = format!("{} --no-deps", clippy_args);
+ let mut clippy_args: Vec<String> = old_args.collect();
+ if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") {
+ clippy_args.push("--no-deps".into());
}
- let has_args = !clippy_args.is_empty();
ClippyCmd {
unstable_options,
cargo_subcommand,
args,
- clippy_args: has_args.then_some(clippy_args),
+ clippy_args,
}
}
.map(|p| ("CARGO_TARGET_DIR", p))
}
- fn into_std_cmd(self, rustflags: Option<String>) -> Command {
+ fn into_std_cmd(self) -> Command {
let mut cmd = Command::new("cargo");
+ let clippy_args: String = self
+ .clippy_args
+ .iter()
+ .map(|arg| format!("{}__CLIPPY_HACKERY__", arg))
+ .collect();
cmd.env(self.path_env(), Self::path())
.envs(ClippyCmd::target_dir())
+ .env("CLIPPY_ARGS", clippy_args)
.arg(self.cargo_subcommand)
.args(&self.args);
- // HACK: pass Clippy args to the driver *also* through RUSTFLAGS.
- // This guarantees that new builds will be triggered when Clippy flags change.
- if let Some(clippy_args) = self.clippy_args {
- cmd.env(
- "RUSTFLAGS",
- rustflags.map_or(clippy_args.clone(), |flags| format!("{} {}", clippy_args, flags)),
- );
- cmd.env("CLIPPY_ARGS", clippy_args);
- }
-
cmd
}
}
{
let cmd = ClippyCmd::new(old_args);
- let mut cmd = cmd.into_std_cmd(env::var("RUSTFLAGS").ok());
+ let mut cmd = cmd.into_std_cmd();
let exit_status = cmd
.spawn()
#[cfg(test)]
mod tests {
use super::ClippyCmd;
- use std::ffi::OsStr;
#[test]
#[should_panic]
.split_whitespace()
.map(ToString::to_string);
let cmd = ClippyCmd::new(args);
-
assert_eq!("fix", cmd.cargo_subcommand);
assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env());
assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options")));
.split_whitespace()
.map(ToString::to_string);
let cmd = ClippyCmd::new(args);
-
- assert!(cmd.clippy_args.unwrap().contains("--no-deps"));
+ assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps"));
}
#[test]
.split_whitespace()
.map(ToString::to_string);
let cmd = ClippyCmd::new(args);
-
- assert_eq!(1, cmd.clippy_args.unwrap().matches("--no-deps").count());
+ assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1);
}
#[test]
fn check() {
let args = "cargo clippy".split_whitespace().map(ToString::to_string);
let cmd = ClippyCmd::new(args);
-
assert_eq!("check", cmd.cargo_subcommand);
assert_eq!("RUSTC_WRAPPER", cmd.path_env());
}
.split_whitespace()
.map(ToString::to_string);
let cmd = ClippyCmd::new(args);
-
assert_eq!("check", cmd.cargo_subcommand);
assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env());
}
-
- #[test]
- fn clippy_args_into_rustflags() {
- let args = "cargo clippy -- -W clippy::as_conversions"
- .split_whitespace()
- .map(ToString::to_string);
- let cmd = ClippyCmd::new(args);
-
- let rustflags = None;
- let cmd = cmd.into_std_cmd(rustflags);
-
- assert!(cmd
- .get_envs()
- .any(|(key, val)| key == "RUSTFLAGS" && val == Some(OsStr::new("-W clippy::as_conversions"))));
- }
-
- #[test]
- fn clippy_args_respect_existing_rustflags() {
- let args = "cargo clippy -- -D clippy::await_holding_lock"
- .split_whitespace()
- .map(ToString::to_string);
- let cmd = ClippyCmd::new(args);
-
- let rustflags = Some(r#"--cfg feature="some_feat""#.into());
- let cmd = cmd.into_std_cmd(rustflags);
-
- assert!(cmd.get_envs().any(|(key, val)| key == "RUSTFLAGS"
- && val == Some(OsStr::new(r#"-D clippy::await_holding_lock --cfg feature="some_feat""#))));
- }
-
- #[test]
- fn no_env_change_if_no_clippy_args() {
- let args = "cargo clippy".split_whitespace().map(ToString::to_string);
- let cmd = ClippyCmd::new(args);
-
- let rustflags = Some(r#"--cfg feature="some_feat""#.into());
- let cmd = cmd.into_std_cmd(rustflags);
-
- assert!(!cmd
- .get_envs()
- .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS"));
- }
-
- #[test]
- fn no_env_change_if_no_clippy_args_nor_rustflags() {
- let args = "cargo clippy".split_whitespace().map(ToString::to_string);
- let cmd = ClippyCmd::new(args);
-
- let rustflags = None;
- let cmd = cmd.into_std_cmd(rustflags);
-
- assert!(!cmd
- .get_envs()
- .any(|(key, _)| key == "RUSTFLAGS" || key == "CLIPPY_ARGS"))
- }
}
.current_dir(root_dir)
.env("CLIPPY_DOGFOOD", "1")
.env("CARGO_INCREMENTAL", "0")
- .arg("clippy")
+ .arg("clippy-preview")
.arg("--all-targets")
.arg("--all-features")
.arg("--")
B(i32),
C,
D,
- };
+ }
let x = E::A(2);
{
// lint
B(i32),
C,
D,
- };
+ }
let x = E::A(2);
{
// lint
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Mode {
- CompileFail,
- RunFail,
RunPassValgrind,
Pretty,
DebugInfo,
type Err = ();
fn from_str(s: &str) -> Result<Mode, ()> {
match s {
- "compile-fail" => Ok(CompileFail),
- "run-fail" => Ok(RunFail),
"run-pass-valgrind" => Ok(RunPassValgrind),
"pretty" => Ok(Pretty),
"debuginfo" => Ok(DebugInfo),
impl fmt::Display for Mode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
- CompileFail => "compile-fail",
- RunFail => "run-fail",
RunPassValgrind => "run-pass-valgrind",
Pretty => "pretty",
DebugInfo => "debuginfo",
/// The name of the stage being built (stage1, etc)
pub stage_id: String,
- /// The test mode, compile-fail, run-fail, ui
+ /// The test mode, e.g. ui or debuginfo.
pub mode: Mode,
/// The test suite (essentially which directory is running, but without the
}
if self.failure_status == -1 {
- self.failure_status = match config.mode {
- Mode::RunFail => 101,
- _ => 1,
- };
+ self.failure_status = 1;
}
if self.should_ice {
self.failure_status = 101;
"",
"mode",
"which sort of compile tests to run",
- "compile-fail | run-fail | run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
+ "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
| rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly",
)
.reqopt(
use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui};
use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc};
use crate::common::{CompareMode, FailMode, PassMode};
-use crate::common::{CompileFail, Pretty, RunFail, RunPassValgrind};
use crate::common::{Config, TestPaths};
+use crate::common::{Pretty, RunPassValgrind};
use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT};
use crate::errors::{self, Error, ErrorKind};
use crate::header::TestProps;
/// revisions, exactly once, with revision == None).
fn run_revision(&self) {
if self.props.should_ice {
- if self.config.mode != CompileFail && self.config.mode != Incremental {
+ if self.config.mode != Incremental {
self.fatal("cannot use should-ice in a test that is not cfail");
}
}
match self.config.mode {
- CompileFail => self.run_cfail_test(),
- RunFail => self.run_rfail_test(),
RunPassValgrind => self.run_valgrind_test(),
Pretty => self.run_pretty_test(),
DebugInfo => self.run_debuginfo_test(),
fn should_compile_successfully(&self, pm: Option<PassMode>) -> bool {
match self.config.mode {
- CompileFail => false,
JsDocTest => true,
Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build),
Incremental => {
};
let allow_unused = match self.config.mode {
- CompileFail | Ui => {
- // compile-fail and ui tests tend to have tons of unused code as
+ Ui => {
+ // UI tests tend to have tons of unused code as
// it's just testing various pieces of the compile, but we don't
// want to actually assert warnings about all this code. Instead
// let's just ignore unused code warnings by defaults and tests
}
match self.config.mode {
- CompileFail | Incremental => {
+ Incremental => {
// If we are extracting and matching errors in the new
// fashion, then you want JSON mode. Old-skool error
// patterns still match the raw compiler output.
rustc.arg(dir_opt);
}
- RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson
- | RunMake | CodegenUnits | JsDocTest | Assembly => {
+ RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson | RunMake
+ | CodegenUnits | JsDocTest | Assembly => {
// do not use JSON output
}
}
result.push('\n');
result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
for lint_name in to_link {
- let lint_def =
- lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
- format!(
- "`rustc -W help` defined lint `{}` but that lint does not appear to exist",
+ let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) {
+ Some(def) => def,
+ None => {
+ let msg = format!(
+ "`rustc -W help` defined lint `{}` but that lint does not \
+ appear to exist\n\
+ Check that the lint definition includes the appropriate doc comments.",
lint_name
- )
- })?;
+ );
+ if self.validate {
+ return Err(msg.into());
+ } else {
+ eprintln!("warning: {}", msg);
+ continue;
+ }
+ }
+ };
write!(
result,
"[{}]: listing/{}#{}\n",
-Subproject commit d66f476b4d5e7fdf1ec215c9ac16c923dc292324
+Subproject commit 5254dbfd25d5284728ab624dca1969d61427a0db
curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
crossbeam-utils = { version = "0.7.2", features = ["nightly"] }
libc = { version = "0.2.79", features = ["align"] }
+# Ensure default features of libz-sys, which are disabled in some scenarios.
+libz-sys = { version = "1.1.2" }
proc-macro2 = { version = "1", features = ["default"] }
quote = { version = "1", features = ["default"] }
serde = { version = "1.0.82", features = ['derive'] }
-Subproject commit 70ce18255f429caf0d75ecfed8c1464535ee779b
+Subproject commit acd94866fd0ff5eacb7e184ae21c19e5440fc5fb
assert!(!lib_features.is_empty());
super::walk_many(
- &[
- &src_path.join("test/ui"),
- &src_path.join("test/ui-fulldeps"),
- &src_path.join("test/compile-fail"),
- ],
+ &[&src_path.join("test/ui"), &src_path.join("test/ui-fulldeps")],
&mut |path| super::filter_dirs(path),
&mut |entry, contents| {
let file = entry.path();
# x
`x` invokes `x.py` from any subdirectory.
+
+To install, run the following commands:
+
+```
+$ cd rust/src/tools/x/
+$ cargo install --path .
+```
[notify-zulip."I-prioritize"]
zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "I-prioritize #{number} {title}"
+topic = "#{number} {title}"
message_on_add = """\
@*WG-prioritization/alerts* issue #{number} has been requested for prioritization.