*.h rust
*.rs rust diff=rust
*.fixed linguist-language=Rust
+*.mir linguist-language=Rust
src/etc/installer/gfx/* binary
*.woff binary
src/vendor/** -text
Joseph Martin <pythoner6@gmail.com>
Joseph T. Lyons <JosephTLyons@gmail.com> <josephtlyons@gmail.com>
Joseph T. Lyons <JosephTLyons@gmail.com> <JosephTLyons@users.noreply.github.com>
+Joshua Nelson <jyn514@gmail.com> <joshua@yottadb.com>
jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com>
Junyoung Cho <june0.cho@samsung.com>
Jyun-Yan You <jyyou.tw@gmail.com> <jyyou@cs.nctu.edu.tw>
Philipp Brüschweiler <blei42@gmail.com> <blei42@gmail.com>
Philipp Brüschweiler <blei42@gmail.com> <bruphili@student.ethz.ch>
Philipp Krones <hello@philkrones.com> flip1995 <hello@philkrones.com>
+Philipp Krones <hello@philkrones.com> <philipp.krones@embecosm.com>
Philipp Matthias Schäfer <philipp.matthias.schaefer@posteo.de>
Przemysław Wesołek <jest@go.art.pl> Przemek Wesołek <jest@go.art.pl>
Rafael Ávila de Espíndola <respindola@mozilla.com> Rafael Avila de Espindola <espindola@dream.(none)>
# It is not intended for manual editing.
[[package]]
name = "addr2line"
-version = "0.13.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
+checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423"
dependencies = [
"compiler_builtins",
"gimli",
[[package]]
name = "backtrace"
-version = "0.3.53"
+version = "0.3.55"
dependencies = [
"addr2line",
"cfg-if 1.0.0",
"libc",
"miniz_oxide",
- "object 0.21.1",
+ "object",
"rustc-demangle",
]
[[package]]
name = "cargo"
-version = "0.50.0"
+version = "0.51.0"
dependencies = [
"anyhow",
"atty",
[[package]]
name = "gimli"
-version = "0.22.0"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
+checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
[[package]]
name = "object"
-version = "0.20.0"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
+checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
-[[package]]
-name = "object"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693"
-
[[package]]
name = "once_cell"
version = "1.4.1"
"rustc_target",
"rustc_trait_selection",
"rustc_traits",
- "rustc_ty",
+ "rustc_ty_utils",
"rustc_typeck",
"smallvec 1.4.2",
"tempfile",
"rustc_hir",
"rustc_index",
"rustc_middle",
+ "rustc_parse_format",
"rustc_session",
"rustc_span",
"rustc_target",
]
[[package]]
-name = "rustc_ty"
+name = "rustc_ty_utils"
version = "0.0.0"
dependencies = [
"rustc_data_structures",
"hermit-abi",
"libc",
"miniz_oxide",
- "object 0.20.0",
+ "object",
"panic_abort",
"panic_unwind",
"profiler_builtins",
"chrono",
"lazy_static",
"matchers",
- "parking_lot 0.9.0",
+ "parking_lot 0.11.0",
"regex",
"serde",
"serde_json",
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(no_crate_inject, attr(deny(warnings)))
)]
+#![feature(array_value_iter_slice)]
#![feature(dropck_eyepatch)]
#![feature(new_uninit)]
#![feature(maybe_uninit_slice)]
+#![feature(array_value_iter)]
+#![feature(min_const_generics)]
+#![feature(min_specialization)]
#![cfg_attr(test, feature(test))]
use smallvec::SmallVec;
}
}
+trait IterExt<T> {
+ fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T];
+}
+
+impl<I, T> IterExt<T> for I
+where
+ I: IntoIterator<Item = T>,
+{
+ #[inline]
+ default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
+ let vec: SmallVec<[_; 8]> = self.into_iter().collect();
+ vec.alloc_from_iter(arena)
+ }
+}
+
+impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> {
+ #[inline]
+ fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
+ let len = self.len();
+ if len == 0 {
+ return &mut [];
+ }
+ // Move the content to the arena by copying and then forgetting it
+ unsafe {
+ let start_ptr = arena.alloc_raw_slice(len);
+ self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len);
+ mem::forget(self);
+ slice::from_raw_parts_mut(start_ptr, len)
+ }
+ }
+}
+
+impl<T> IterExt<T> for Vec<T> {
+ #[inline]
+ fn alloc_from_iter(mut self, arena: &TypedArena<T>) -> &mut [T] {
+ let len = self.len();
+ if len == 0 {
+ return &mut [];
+ }
+ // Move the content to the arena by copying and then forgetting it
+ unsafe {
+ let start_ptr = arena.alloc_raw_slice(len);
+ self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+ self.set_len(0);
+ slice::from_raw_parts_mut(start_ptr, len)
+ }
+ }
+}
+
+impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> {
+ #[inline]
+ fn alloc_from_iter(mut self, arena: &TypedArena<A::Item>) -> &mut [A::Item] {
+ let len = self.len();
+ if len == 0 {
+ return &mut [];
+ }
+ // Move the content to the arena by copying and then forgetting it
+ unsafe {
+ let start_ptr = arena.alloc_raw_slice(len);
+ self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+ self.set_len(0);
+ slice::from_raw_parts_mut(start_ptr, len)
+ }
+ }
+}
+
impl<T> TypedArena<T> {
/// Allocates an object in the `TypedArena`, returning a reference to it.
#[inline]
#[inline]
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
assert!(mem::size_of::<T>() != 0);
- let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
- if vec.is_empty() {
- return &mut [];
- }
- // Move the content to the arena by copying it and then forgetting
- // the content of the SmallVec
- unsafe {
- let len = vec.len();
- let start_ptr = self.alloc_raw_slice(len);
- vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
- vec.set_len(0);
- slice::from_raw_parts_mut(start_ptr, len)
- }
+ iter.alloc_from_iter(self)
}
/// Grows the arena.
pub id: NodeId,
pub kind: StmtKind,
pub span: Span,
- pub tokens: Option<LazyTokenStream>,
}
impl Stmt {
+ pub fn tokens(&self) -> Option<&LazyTokenStream> {
+ match self.kind {
+ StmtKind::Local(ref local) => local.tokens.as_ref(),
+ StmtKind::Item(ref item) => item.tokens.as_ref(),
+ StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.tokens.as_ref(),
+ StmtKind::Empty => None,
+ StmtKind::MacCall(ref mac) => mac.tokens.as_ref(),
+ }
+ }
+
+ pub fn tokens_mut(&mut self) -> Option<&mut LazyTokenStream> {
+ match self.kind {
+ StmtKind::Local(ref mut local) => local.tokens.as_mut(),
+ StmtKind::Item(ref mut item) => item.tokens.as_mut(),
+ StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.tokens.as_mut(),
+ StmtKind::Empty => None,
+ StmtKind::MacCall(ref mut mac) => mac.tokens.as_mut(),
+ }
+ }
+
+ pub fn set_tokens(&mut self, tokens: Option<LazyTokenStream>) {
+ match self.kind {
+ StmtKind::Local(ref mut local) => local.tokens = tokens,
+ StmtKind::Item(ref mut item) => item.tokens = tokens,
+ StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.tokens = tokens,
+ StmtKind::Empty => {}
+ StmtKind::MacCall(ref mut mac) => mac.tokens = tokens,
+ }
+ }
+
pub fn has_trailing_semicolon(&self) -> bool {
match &self.kind {
StmtKind::Semi(_) => true,
_ => false,
}
}
+
+ /// Converts a parsed `Stmt` to a `Stmt` with
+ /// a trailing semicolon.
+ ///
+ /// This only modifies the parsed AST struct, not the attached
+ /// `LazyTokenStream`. The parser is responsible for calling
+ /// `CreateTokenStream::add_trailing_semi` when there is actually
+ /// a semicolon in the tokenstream.
pub fn add_trailing_semicolon(mut self) -> Self {
self.kind = match self.kind {
StmtKind::Expr(expr) => StmtKind::Semi(expr),
StmtKind::MacCall(mac) => {
- StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs }| MacCallStmt {
- mac,
- style: MacStmtStyle::Semicolon,
- attrs,
+ StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs, tokens }| {
+ MacCallStmt { mac, style: MacStmtStyle::Semicolon, attrs, tokens }
}))
}
kind => kind,
};
+
self
}
pub mac: MacCall,
pub style: MacStmtStyle,
pub attrs: AttrVec,
+ pub tokens: Option<LazyTokenStream>,
}
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
pub init: Option<P<Expr>>,
pub span: Span,
pub attrs: AttrVec,
+ pub tokens: Option<LazyTokenStream>,
}
/// An arm of a 'match'.
pub struct AssocTyConstraint {
pub id: NodeId,
pub ident: Ident,
+ pub gen_args: Option<GenericArgs>,
pub kind: AssocTyConstraintKind,
pub span: Span,
}
pub mod util {
pub mod classify;
pub mod comments;
- pub mod lev_distance;
pub mod literal;
pub mod parser;
}
}
pub fn noop_visit_ty_constraint<T: MutVisitor>(
- AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
+ AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
vis: &mut T,
) {
vis.visit_id(id);
vis.visit_ident(ident);
+ if let Some(ref mut gen_args) = gen_args {
+ vis.visit_generic_args(gen_args);
+ }
match kind {
AssocTyConstraintKind::Equality { ref mut ty } => {
vis.visit_ty(ty);
}
pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
- let Local { id, pat, ty, init, span, attrs } = local.deref_mut();
+ let Local { id, pat, ty, init, span, attrs, tokens } = local.deref_mut();
vis.visit_id(id);
vis.visit_pat(pat);
visit_opt(ty, |ty| vis.visit_ty(ty));
visit_opt(init, |init| vis.visit_expr(init));
vis.visit_span(span);
visit_thin_attrs(attrs, vis);
+ visit_lazy_tts(tokens, vis);
}
pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
}
pub fn noop_flat_map_stmt<T: MutVisitor>(
- Stmt { kind, mut span, mut id, mut tokens }: Stmt,
+ Stmt { kind, mut span, mut id }: Stmt,
vis: &mut T,
) -> SmallVec<[Stmt; 1]> {
vis.visit_id(&mut id);
vis.visit_span(&mut span);
- visit_lazy_tts(&mut tokens, vis);
- noop_flat_map_stmt_kind(kind, vis)
- .into_iter()
- .map(|kind| Stmt { id, kind, span, tokens: tokens.clone() })
- .collect()
+ noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect()
}
pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(),
StmtKind::Empty => smallvec![StmtKind::Empty],
StmtKind::MacCall(mut mac) => {
- let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut();
+ let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut();
vis.visit_mac_call(mac_);
visit_thin_attrs(attrs, vis);
+ visit_lazy_tts(tokens, vis);
smallvec![StmtKind::MacCall(mac)]
}
}
/// See issue #73345 for more details.
/// FIXME(#73933): Remove this eventually.
pub fn pretty_printing_compatibility_hack(&self) -> bool {
- if let NtItem(item) = self {
- let name = item.ident.name;
- if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack {
- if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
- if let [variant] = &*enum_def.variants {
- return variant.ident.name == sym::Input;
- }
+ let item = match self {
+ NtItem(item) => item,
+ NtStmt(stmt) => match &stmt.kind {
+ ast::StmtKind::Item(item) => item,
+ _ => return false,
+ },
+ _ => return false,
+ };
+
+ let name = item.ident.name;
+ if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack {
+ if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
+ if let [variant] = &*enum_def.variants {
+ return variant.ident.name == sym::Input;
}
}
}
}
pub trait CreateTokenStream: sync::Send + sync::Sync {
+ fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream>;
fn create_token_stream(&self) -> TokenStream;
}
impl CreateTokenStream for TokenStream {
+ fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> {
+ panic!("Cannot call `add_trailing_semi` on a `TokenStream`!");
+ }
fn create_token_stream(&self) -> TokenStream {
self.clone()
}
LazyTokenStream(Lrc::new(Box::new(inner)))
}
+ /// Extends the captured stream by one token,
+ /// which must be a trailing semicolon. This
+ /// affects the `TokenStream` created by `make_tokenstream`.
+ pub fn add_trailing_semi(&self) -> LazyTokenStream {
+ LazyTokenStream(Lrc::new(self.0.add_trailing_semi()))
+ }
+
pub fn create_token_stream(&self) -> TokenStream {
self.0.create_token_stream()
}
+++ /dev/null
-// FIXME(Centril): Move to rustc_span?
-
-use rustc_span::symbol::Symbol;
-use std::cmp;
-
-#[cfg(test)]
-mod tests;
-
-/// 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() {
- return b.chars().count();
- } else if b.is_empty() {
- return a.chars().count();
- }
-
- let mut dcol: Vec<_> = (0..=b.len()).collect();
- let mut t_last = 0;
-
- for (i, sc) in a.chars().enumerate() {
- let mut current = i;
- dcol[0] = current + 1;
-
- for (j, tc) in b.chars().enumerate() {
- let next = dcol[j + 1];
- if sc == tc {
- dcol[j + 1] = current;
- } else {
- dcol[j + 1] = cmp::min(current, next);
- dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
- }
- current = next;
- t_last = j;
- }
- }
- dcol[t_last + 1]
-}
-
-/// 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.
-pub fn find_best_match_for_name<'a, T>(
- iter_names: T,
- lookup: Symbol,
- dist: Option<usize>,
-) -> Option<Symbol>
-where
- T: Iterator<Item = &'a Symbol>,
-{
- let lookup = &lookup.as_str();
- let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
- let name_vec: Vec<&Symbol> = iter_names.collect();
-
- let (case_insensitive_match, levenshtein_match) = name_vec
- .iter()
- .filter_map(|&name| {
- let dist = lev_distance(lookup, &name.as_str());
- if dist <= max_dist { Some((name, dist)) } else { None }
- })
- // Here we are collecting the next structure:
- // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
- .fold((None, None), |result, (candidate, dist)| {
- (
- if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
- Some(candidate)
- } else {
- result.0
- },
- match result.1 {
- None => Some((candidate, dist)),
- Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
- },
- )
- });
- // Priority of matches:
- // 1. Exact case insensitive match
- // 2. Levenshtein distance match
- // 3. Sorted word match
- if let Some(candidate) = case_insensitive_match {
- Some(*candidate)
- } else if levenshtein_match.is_some() {
- levenshtein_match.map(|(candidate, _)| *candidate)
- } else {
- find_match_by_sorted_words(name_vec, lookup)
- }
-}
-
-fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> Option<Symbol> {
- iter_names.iter().fold(None, |result, candidate| {
- if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) {
- Some(**candidate)
- } else {
- result
- }
- })
-}
-
-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
- split_words.sort_unstable();
- split_words.join("_")
-}
+++ /dev/null
-use super::*;
-
-#[test]
-fn test_lev_distance() {
- use std::char::{from_u32, MAX};
- // Test bytelength agnosticity
- for c in (0..MAX as u32).filter_map(|i| from_u32(i)).map(|i| i.to_string()) {
- assert_eq!(lev_distance(&c[..], &c[..]), 0);
- }
-
- let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
- let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
- let c = "Mary häd ä little lämb\n\nLittle lämb\n";
- assert_eq!(lev_distance(a, b), 1);
- assert_eq!(lev_distance(b, a), 1);
- assert_eq!(lev_distance(a, c), 2);
- assert_eq!(lev_distance(c, a), 2);
- assert_eq!(lev_distance(b, c), 1);
- assert_eq!(lev_distance(c, b), 1);
-}
-
-#[test]
-fn test_find_best_match_for_name() {
- use rustc_span::with_default_session_globals;
- with_default_session_globals(|| {
- let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")];
- assert_eq!(
- find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None),
- Some(Symbol::intern("aaab"))
- );
-
- assert_eq!(
- find_best_match_for_name(input.iter(), Symbol::intern("1111111111"), None),
- None
- );
-
- let input = vec![Symbol::intern("aAAA")];
- assert_eq!(
- find_best_match_for_name(input.iter(), Symbol::intern("AAAA"), None),
- Some(Symbol::intern("aAAA"))
- );
-
- let input = vec![Symbol::intern("AAAA")];
- // Returns None because `lev_distance > max_dist / 3`
- assert_eq!(find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None), None);
-
- let input = vec![Symbol::intern("AAAA")];
- assert_eq!(
- find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), Some(4)),
- Some(Symbol::intern("AAAA"))
- );
-
- let input = vec![Symbol::intern("a_longer_variable_name")];
- assert_eq!(
- find_best_match_for_name(input.iter(), Symbol::intern("a_variable_longer_name"), None),
- Some(Symbol::intern("a_longer_variable_name"))
- );
- })
-}
constraint: &'a AssocTyConstraint,
) {
visitor.visit_ident(constraint.ident);
+ if let Some(ref gen_args) = constraint.gen_args {
+ visitor.visit_generic_args(gen_args.span(), gen_args);
+ }
match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => {
visitor.visit_ty(ty);
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr),
StmtKind::Empty => {}
StmtKind::MacCall(ref mac) => {
- let MacCallStmt { ref mac, style: _, ref attrs } = **mac;
+ let MacCallStmt { ref mac, style: _, ref attrs, tokens: _ } = **mac;
visitor.visit_mac_call(mac);
for attr in attrs.iter() {
visitor.visit_attribute(attr);
let else_arm = self.arm(else_pat, else_expr);
// Handle then + scrutinee:
- let then_expr = self.lower_block_expr(then);
let (then_pat, scrutinee, desugar) = match cond.kind {
// `<pat> => <then>`:
ExprKind::Let(ref pat, ref scrutinee) => {
(pat, cond, hir::MatchSource::IfDesugar { contains_else_clause })
}
};
+ let then_expr = self.lower_block_expr(then);
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar)
};
// Handle then + scrutinee:
- let then_expr = self.lower_block_expr(body);
let (then_pat, scrutinee, desugar, source) = match cond.kind {
ExprKind::Let(ref pat, ref scrutinee) => {
// to:
(pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
}
};
+ let then_expr = self.lower_block_expr(body);
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
// `match <scrutinee> { ... }`
items: BTreeSet::new(),
trait_items: BTreeSet::new(),
impl_items: BTreeSet::new(),
+ foreign_items: BTreeSet::new(),
},
);
visit::walk_assoc_item(self, item, ctxt);
}
+
+ fn visit_foreign_item(&mut self, item: &'a ForeignItem) {
+ self.lctx.allocate_hir_id_counter(item.id);
+ self.lctx.with_hir_id_owner(item.id, |lctx| {
+ let hir_item = lctx.lower_foreign_item(item);
+ let id = hir::ForeignItemId { hir_id: hir_item.hir_id };
+ lctx.foreign_items.insert(id, hir_item);
+ lctx.modules.get_mut(&lctx.current_module).unwrap().foreign_items.insert(id);
+ });
+
+ visit::walk_foreign_item(self, item);
+ }
}
impl<'hir> LoweringContext<'_, 'hir> {
})
}
ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
- ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
+ ItemKind::ForeignMod(ref fm) => hir::ItemKind::ForeignMod {
+ abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
+ items: self
+ .arena
+ .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
+ },
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => {
// We lower
}
}
- fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod<'hir> {
- hir::ForeignMod {
- abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
- items: self.arena.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item(x))),
+ fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef<'hir> {
+ hir::ForeignItemRef {
+ id: hir::ForeignItemId { hir_id: self.lower_node_id(i.id) },
+ ident: i.ident,
+ span: i.span,
+ vis: self.lower_visibility(&i.vis, Some(i.id)),
}
}
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem<'hir>>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem<'hir>>,
+ foreign_items: BTreeMap<hir::ForeignItemId, hir::ForeignItem<'hir>>,
bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
exported_macros: Vec<hir::MacroDef<'hir>>,
non_exported_macro_attrs: Vec<ast::Attribute>,
items: BTreeMap::new(),
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
+ foreign_items: BTreeMap::new(),
bodies: BTreeMap::new(),
trait_impls: BTreeMap::new(),
modules: BTreeMap::new(),
/// declared for every type and trait definition.
struct MiscCollector<'tcx, 'lowering, 'hir> {
lctx: &'tcx mut LoweringContext<'lowering, 'hir>,
- hir_id_owner: Option<NodeId>,
}
impl MiscCollector<'_, '_, '_> {
}
}
}
-
- fn with_hir_id_owner<T>(
- &mut self,
- owner: Option<NodeId>,
- f: impl FnOnce(&mut Self) -> T,
- ) -> T {
- let old = mem::replace(&mut self.hir_id_owner, owner);
- let r = f(self);
- self.hir_id_owner = old;
- r
- }
}
impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> {
- fn visit_pat(&mut self, p: &'tcx Pat) {
- if let PatKind::Paren(..) | PatKind::Rest = p.kind {
- // Doesn't generate a HIR node
- } else if let Some(owner) = self.hir_id_owner {
- self.lctx.lower_node_id_with_owner(p.id, owner);
- }
-
- visit::walk_pat(self, p)
- }
-
fn visit_item(&mut self, item: &'tcx Item) {
let hir_id = self.lctx.allocate_hir_id_counter(item.id);
_ => {}
}
- self.with_hir_id_owner(Some(item.id), |this| {
- visit::walk_item(this, item);
- });
+ visit::walk_item(self, item);
}
fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) {
self.lctx.allocate_hir_id_counter(item.id);
- let owner = match (&item.kind, ctxt) {
- // Ignore patterns in trait methods without bodies.
- (AssocItemKind::Fn(_, _, _, None), AssocCtxt::Trait) => None,
- _ => Some(item.id),
- };
- self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt));
+ visit::walk_assoc_item(self, item, ctxt);
}
- fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
- // Ignore patterns in foreign items
- self.with_hir_id_owner(None, |this| visit::walk_foreign_item(this, i));
+ fn visit_foreign_item(&mut self, item: &'tcx ForeignItem) {
+ self.lctx.allocate_hir_id_counter(item.id);
+ visit::walk_foreign_item(self, item);
}
fn visit_ty(&mut self, t: &'tcx Ty) {
// Mirrors visit::walk_fn_decl
for parameter in &f.decl.inputs {
// We don't lower the ids of argument patterns
- self.with_hir_id_owner(None, |this| {
- this.visit_pat(¶meter.pat);
- });
+ self.visit_pat(¶meter.pat);
self.visit_ty(¶meter.ty)
}
self.visit_fn_ret_ty(&f.decl.output)
}
TyKind::ImplTrait(def_node_id, _) => {
self.lctx.allocate_hir_id_counter(def_node_id);
- self.with_hir_id_owner(Some(def_node_id), |this| {
- visit::walk_ty(this, t);
- });
+ visit::walk_ty(self, t);
}
_ => visit::walk_ty(self, t),
}
self.lower_node_id(CRATE_NODE_ID);
debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == Some(hir::CRATE_HIR_ID));
- visit::walk_crate(&mut MiscCollector { lctx: &mut self, hir_id_owner: None }, c);
+ visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
let module = self.lower_mod(&c.module);
items: self.items,
trait_items: self.trait_items,
impl_items: self.impl_items,
+ foreign_items: self.foreign_items,
bodies: self.bodies,
body_ids,
trait_impls: self.trait_impls,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
+ if let Some(ref gen_args) = constraint.gen_args {
+ self.sess.span_fatal(
+ gen_args.span(),
+ "generic associated types in trait paths are currently not implemented",
+ );
+ }
+
let kind = match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => {
hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
self.err_handler()
.struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
.span_label(self.current_extern_span(), "in this `extern` block")
- .span_suggestion(
+ .span_suggestion_verbose(
span.until(ident.span.shrink_to_lo()),
"remove the qualifiers",
"fn ".to_string(),
if param.ident == *ident {
let param = ident;
match &full_path.segments[qself.position..] {
- [PathSegment { ident, .. }] => {
+ [PathSegment { ident, args, .. }] => {
// Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
let mut assoc_path = full_path.clone();
// Remove `Bar` from `Foo::Bar`.
assoc_path.segments.pop();
let len = assoc_path.segments.len() - 1;
+ let gen_args = args.as_ref().map(|p| (**p).clone());
// Build `<Bar = RhsTy>`.
let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
id: rustc_ast::node_id::DUMMY_NODE_ID,
ident: *ident,
+ gen_args,
kind: AssocTyConstraintKind::Equality {
ty: predicate.rhs_ty.clone(),
},
ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
gate_feature_post!(
&self,
- optin_builtin_traits,
+ auto_traits,
i.span,
"auto traits are experimental and possibly buggy"
);
#![feature(bindings_after_at)]
#![feature(iter_is_partitioned)]
+#![recursion_limit = "256"]
pub mod ast_validation;
pub mod feature_gate;
}
}
-#[derive(Clone, PartialEq, Encodable, Decodable)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable)]
pub enum InlineAttr {
None,
Hint,
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, TokenKind};
-use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use rustc_ast::token;
+use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_expand::base::*;
// `core::panic` and `std::panic` are different macros, so we use call-site
// context to pick up whichever is currently in scope.
let sp = cx.with_call_site_ctxt(sp);
- let tokens = custom_message.unwrap_or_else(|| {
- TokenStream::from(TokenTree::token(
- TokenKind::lit(
- token::Str,
+
+ let panic_call = if let Some(tokens) = custom_message {
+ // Pass the custom message to panic!().
+ cx.expr(
+ sp,
+ ExprKind::MacCall(MacCall {
+ path: Path::from_ident(Ident::new(sym::panic, sp)),
+ args: P(MacArgs::Delimited(
+ DelimSpan::from_single(sp),
+ MacDelimiter::Parenthesis,
+ tokens,
+ )),
+ prior_type_ascription: None,
+ }),
+ )
+ } else {
+ // Pass our own message directly to $crate::panicking::panic(),
+ // because it might contain `{` and `}` that should always be
+ // passed literally.
+ cx.expr_call_global(
+ sp,
+ cx.std_path(&[sym::panicking, sym::panic]),
+ vec![cx.expr_str(
+ DUMMY_SP,
Symbol::intern(&format!(
"assertion failed: {}",
pprust::expr_to_string(&cond_expr).escape_debug()
)),
- None,
- ),
- DUMMY_SP,
- ))
- });
- let args = P(MacArgs::Delimited(DelimSpan::from_single(sp), MacDelimiter::Parenthesis, tokens));
- let panic_call = MacCall {
- path: Path::from_ident(Ident::new(sym::panic, sp)),
- args,
- prior_type_ascription: None,
+ )],
+ )
};
- let if_expr = cx.expr_if(
- sp,
- cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)),
- cx.expr(sp, ExprKind::MacCall(panic_call)),
- None,
- );
+ let if_expr =
+ cx.expr_if(sp, cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), panic_call, None);
MacEager::expr(if_expr)
}
//! Implementation of the `#[cfg_accessible(path)]` attribute macro.
use rustc_ast as ast;
-use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
+use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
use rustc_feature::AttributeTemplate;
use rustc_parse::validate_attr;
use rustc_span::symbol::sym;
fn expand(
&self,
ecx: &mut ExtCtxt<'_>,
- _span: Span,
+ span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
None => return ExpandResult::Ready(Vec::new()),
};
- let failure_msg = "cannot determine whether the path is accessible or not";
match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) {
Ok(true) => ExpandResult::Ready(vec![item]),
Ok(false) => ExpandResult::Ready(Vec::new()),
- Err(_) => ExpandResult::Retry(item, failure_msg.into()),
+ Err(Indeterminate) if ecx.force_mode => {
+ ecx.span_err(span, "cannot determine whether the path is accessible or not");
+ ExpandResult::Ready(vec![item])
+ }
+ Err(Indeterminate) => ExpandResult::Retry(item),
}
}
}
id: ast::DUMMY_NODE_ID,
span: sp,
attrs: ast::AttrVec::new(),
+ tokens: None,
});
- ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp, tokens: None }
+ ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
}
_ => false,
})
}
- _ => {
- // Non-ADT derive is an error, but it should have been
- // set earlier; see
- // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
- // librustc_expand/base.rs:Annotatable::derive_allowed()
- return;
- }
+ _ => unreachable!(),
};
let container_id = cx.current_expansion.id.expn_data().parent;
let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id);
);
push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
}
- _ => {
- // Non-Item derive is an error, but it should have been
- // set earlier; see
- // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
- // librustc_expand/base.rs:Annotatable::derive_allowed()
- }
+ _ => unreachable!(),
}
}
// so we are doing it here in a centralized way.
let span = ecx.with_def_site_ctxt(span);
let mut items = Vec::new();
- (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
+ match item {
+ Annotatable::Stmt(stmt) => {
+ if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
+ (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| {
+ // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
+ // to the function
+ items.push(Annotatable::Stmt(P(ast::Stmt {
+ id: ast::DUMMY_NODE_ID,
+ kind: ast::StmtKind::Item(a.expect_item()),
+ span,
+ })));
+ });
+ } else {
+ unreachable!("should have already errored on non-item statement")
+ }
+ }
+ _ => {
+ (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
+ }
+ }
ExpandResult::Ready(items)
}
}
) {
let item = match *item {
Annotatable::Item(ref item) => item,
- _ => {
- // Non-Item derive is an error, but it should have been
- // set earlier; see
- // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
- // librustc_expand/base.rs:Annotatable::derive_allowed()
- return;
- }
+ _ => unreachable!(),
};
let generics = match item.kind {
impl<'a> Iterator for Substitutions<'a> {
type Item = Substitution<'a>;
fn next(&mut self) -> Option<Self::Item> {
- match parse_next_substitution(self.s) {
- Some((mut sub, tail)) => {
- self.s = tail;
- if let Some(InnerSpan { start, end }) = sub.position() {
- sub.set_position(start + self.pos, end + self.pos);
- self.pos += end;
- }
- Some(sub)
- }
- None => None,
+ let (mut sub, tail) = parse_next_substitution(self.s)?;
+ self.s = tail;
+ if let Some(InnerSpan { start, end }) = sub.position() {
+ sub.set_position(start + self.pos, end + self.pos);
+ self.pos += end;
}
+ Some(sub)
}
fn size_hint(&self) -> (usize, Option<usize>) {
AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
};
use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param};
+use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
use rustc_ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
ecx: &mut ExtCtxt<'_>,
_span: Span,
meta_item: &ast::MetaItem,
- item: Annotatable,
+ mut item: Annotatable,
) -> Vec<Annotatable> {
check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator);
ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
vec![item]
};
+ let orig_item = item.clone();
+ let mut is_stmt = false;
+
+ // Allow using `#[global_allocator]` on an item statement
+ if let Annotatable::Stmt(stmt) = &item {
+ if let StmtKind::Item(item_) = &stmt.kind {
+ item = Annotatable::Item(item_.clone());
+ is_stmt = true;
+ }
+ }
+
let item = match item {
Annotatable::Item(item) => match item.kind {
ItemKind::Static(..) => item,
let const_ty = ecx.ty(span, TyKind::Tup(Vec::new()));
let const_body = ecx.expr_block(ecx.block(span, stmts));
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
+ let const_item = if is_stmt {
+ Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
+ } else {
+ Annotatable::Item(const_item)
+ };
// Return the original item and the new methods.
- vec![Annotatable::Item(item), Annotatable::Item(const_item)]
+ vec![orig_item, const_item]
}
struct AllocFnFactory<'a, 'b> {
use rustc_ast as ast;
use rustc_ast::attr;
+use rustc_ast::ptr::P;
use rustc_ast_pretty::pprust;
use rustc_expand::base::*;
use rustc_session::Session;
return vec![];
}
- let item = match item {
- Annotatable::Item(i) => i,
+ let (item, is_stmt) = match item {
+ Annotatable::Item(i) => (i, false),
+ Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => {
+ // FIXME: Use an 'if let' guard once they are implemented
+ if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
+ (i, true)
+ } else {
+ unreachable!()
+ }
+ }
other => {
cx.struct_span_err(
other.span(),
tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
- vec![
- // Access to libtest under a hygienic name
- Annotatable::Item(test_extern),
- // The generated test case
- Annotatable::Item(test_const),
- // The original item
- Annotatable::Item(item),
- ]
+ if is_stmt {
+ vec![
+ // Access to libtest under a hygienic name
+ Annotatable::Stmt(P(cx.stmt_item(sp, test_extern))),
+ // The generated test case
+ Annotatable::Stmt(P(cx.stmt_item(sp, test_const))),
+ // The original item
+ Annotatable::Stmt(P(cx.stmt_item(sp, item))),
+ ]
+ } else {
+ vec![
+ // Access to libtest under a hygienic name
+ Annotatable::Item(test_extern),
+ // The generated test case
+ Annotatable::Item(test_const),
+ // The original item
+ Annotatable::Item(item),
+ ]
+ }
}
fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String {
all(target_arch = "wasm32", not(target_os = "emscripten")),
feature(integer_atomics, stdsimd)
)]
-#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
+#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(target_arch = "x86",
/// independently of the standard library’s global allocator.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
pub struct System;
-#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
+#[cfg(any(windows, unix, target_os = "redox"))]
mod realloc_fallback {
use core::alloc::{GlobalAlloc, Layout};
use core::cmp;
}
}
}
-#[cfg(any(unix, target_os = "cloudabi", target_os = "redox"))]
+#[cfg(any(unix, target_os = "redox"))]
mod platform {
extern crate libc;
use core::ptr;
#![feature(
no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
- untagged_unions, decl_macro, rustc_attrs, transparent_unions, optin_builtin_traits,
+ untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits,
thread_local,
)]
#![no_core]
where
F: FnMut(llvm::Attribute),
{
- for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
+ for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg)
}
}
pub trait ArgAttributesExt {
- fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>);
- fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>);
+ fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value);
+ fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value);
}
impl ArgAttributesExt for ArgAttributes {
- fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) {
+ fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value) {
let mut regular = self.regular;
unsafe {
let deref = self.pointee_size.bytes();
if let Some(align) = self.pointee_align {
llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
}
- if regular.contains(ArgAttribute::ByVal) {
- llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap());
- }
regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
+ match self.arg_ext {
+ ArgExtension::None => {}
+ ArgExtension::Zext => {
+ llvm::Attribute::ZExt.apply_llfn(idx, llfn);
+ }
+ ArgExtension::Sext => {
+ llvm::Attribute::SExt.apply_llfn(idx, llfn);
+ }
+ }
}
}
- fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) {
+ fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value) {
let mut regular = self.regular;
unsafe {
let deref = self.pointee_size.bytes();
align.bytes() as u32,
);
}
- if regular.contains(ArgAttribute::ByVal) {
- llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap());
- }
regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
+ match self.arg_ext {
+ ArgExtension::None => {}
+ ArgExtension::Zext => {
+ llvm::Attribute::ZExt.apply_callsite(idx, callsite);
+ }
+ ArgExtension::Sext => {
+ llvm::Attribute::SExt.apply_callsite(idx, callsite);
+ }
+ }
}
}
}
.prefix
.iter()
.flat_map(|option_kind| {
- option_kind.map(|kind| Reg { kind, size: self.prefix_chunk }.llvm_type(cx))
+ option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
})
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();
PassMode::Pair(..) => {
OperandValue::Pair(next(), next()).store(bx, dst);
}
- PassMode::Indirect(_, Some(_)) => {
+ PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
}
- PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => {
+ PassMode::Direct(_)
+ | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
+ | PassMode::Cast(_) => {
let next_arg = next();
self.store(bx, next_arg, dst);
}
if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
).sum();
let mut llargument_tys = Vec::with_capacity(
- if let PassMode::Indirect(..) = self.ret.mode { 1 } else { 0 } + args_capacity,
+ if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } + args_capacity,
);
let llreturn_ty = match self.ret.mode {
PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
PassMode::Cast(cast) => cast.llvm_type(cx),
- PassMode::Indirect(..) => {
+ PassMode::Indirect { .. } => {
llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
cx.type_void()
}
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
continue;
}
- PassMode::Indirect(_, Some(_)) => {
+ PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty);
let ptr_layout = cx.layout_of(ptr_ty);
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true));
continue;
}
PassMode::Cast(cast) => cast.llvm_type(cx),
- PassMode::Indirect(_, None) => cx.type_ptr_to(arg.memory_ty(cx)),
+ PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+ cx.type_ptr_to(arg.memory_ty(cx))
+ }
};
llargument_tys.push(llarg_ty);
}
}
let mut i = 0;
- let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
- attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
+ let mut apply = |attrs: &ArgAttributes| {
+ attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), llfn);
i += 1;
+ i - 1
};
match self.ret.mode {
PassMode::Direct(ref attrs) => {
- attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None);
+ attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, llfn);
+ }
+ PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
+ assert!(!on_stack);
+ let i = apply(attrs);
+ llvm::Attribute::StructRet.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
}
- PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))),
_ => {}
}
for arg in &self.args {
if arg.pad.is_some() {
- apply(&ArgAttributes::new(), None);
+ apply(&ArgAttributes::new());
}
match arg.mode {
PassMode::Ignore => {}
- PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => {
- apply(attrs, Some(arg.layout.llvm_type(cx)))
+ PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
+ let i = apply(attrs);
+ unsafe {
+ llvm::LLVMRustAddByValAttr(
+ llfn,
+ llvm::AttributePlace::Argument(i).as_uint(),
+ arg.layout.llvm_type(cx),
+ );
+ }
}
- PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
- apply(attrs, None);
- apply(extra_attrs, None);
+ PassMode::Direct(ref attrs)
+ | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
+ apply(attrs);
+ }
+ PassMode::Indirect { ref attrs, extra_attrs: Some(ref extra_attrs), on_stack } => {
+ assert!(!on_stack);
+ apply(attrs);
+ apply(extra_attrs);
}
PassMode::Pair(ref a, ref b) => {
- apply(a, None);
- apply(b, None);
+ apply(a);
+ apply(b);
+ }
+ PassMode::Cast(_) => {
+ apply(&ArgAttributes::new());
}
- PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
}
}
}
// FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite.
let mut i = 0;
- let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
- attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty);
+ let mut apply = |attrs: &ArgAttributes| {
+ attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), callsite);
i += 1;
+ i - 1
};
match self.ret.mode {
PassMode::Direct(ref attrs) => {
- attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None);
+ attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, callsite);
+ }
+ PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
+ assert!(!on_stack);
+ let i = apply(attrs);
+ llvm::Attribute::StructRet
+ .apply_callsite(llvm::AttributePlace::Argument(i), callsite);
}
- PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))),
_ => {}
}
if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi {
}
for arg in &self.args {
if arg.pad.is_some() {
- apply(&ArgAttributes::new(), None);
+ apply(&ArgAttributes::new());
}
match arg.mode {
PassMode::Ignore => {}
- PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => {
- apply(attrs, Some(arg.layout.llvm_type(bx)))
+ PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
+ let i = apply(attrs);
+ unsafe {
+ llvm::LLVMRustAddByValCallSiteAttr(
+ callsite,
+ llvm::AttributePlace::Argument(i).as_uint(),
+ arg.layout.llvm_type(bx),
+ );
+ }
}
- PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
- apply(attrs, None);
- apply(extra_attrs, None);
+ PassMode::Direct(ref attrs)
+ | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
+ apply(attrs);
+ }
+ PassMode::Indirect {
+ ref attrs,
+ extra_attrs: Some(ref extra_attrs),
+ on_stack: _,
+ } => {
+ apply(attrs);
+ apply(extra_attrs);
}
PassMode::Pair(ref a, ref b) => {
- apply(a, None);
- apply(b, None);
+ apply(a);
+ apply(b);
+ }
+ PassMode::Cast(_) => {
+ apply(&ArgAttributes::new());
}
- PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
}
}
/// Mark LLVM function to use provided inline heuristic.
#[inline]
-fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr, requires_inline: bool) {
+fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
use self::InlineAttr::*;
match inline {
Hint => Attribute::InlineHint.apply_llfn(Function, val),
Attribute::NoInline.apply_llfn(Function, val);
}
}
- None if requires_inline => Attribute::InlineHint.apply_llfn(Function, val),
None => {}
};
}
}
}
- inline(cx, llfn, codegen_fn_attrs.inline.clone(), instance.def.requires_inline(cx.tcx));
+ let inline_attr = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+ InlineAttr::Never
+ } else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
+ InlineAttr::Hint
+ } else {
+ codegen_fn_attrs.inline
+ };
+ inline(cx, llfn, inline_attr);
// The `uwtable` attribute according to LLVM is:
//
let features = features.join(",");
let features = CString::new(features).unwrap();
let abi = SmallCStr::new(&sess.target.llvm_abiname);
- let trap_unreachable = sess.target.trap_unreachable;
+ let trap_unreachable =
+ sess.opts.debugging_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable);
let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
let asm_comments = sess.asm_comments();
use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
-use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods};
+use rustc_codegen_ssa::traits::ConstMethods;
use rustc_data_structures::fx::FxIndexSet;
use rustc_llvm::RustString;
use rustc_middle::mir::coverage::CodeRegion;
/// Generates and exports the Coverage Map.
///
-/// This Coverage Map complies with Coverage Mapping Format version 3 (zero-based encoded as 2),
-/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format)
-/// and published in Rust's current (July 2020) fork of LLVM. This version is supported by the
+/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3),
+/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format)
+/// and published in Rust's current (November 2020) fork of LLVM. This version is supported by the
/// LLVM coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM.
///
/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
/// undocumented details in Clang's implementation (that may or may not be important) were also
/// replicated for Rust's Coverage Map.
pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
+ // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3).
+ // If not, the LLVM Version must be less than 11.
+ let version = coverageinfo::mapping_version();
+ if version != 3 {
+ cx.tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher.");
+ }
+
let function_coverage_map = match cx.coverage_context() {
Some(ctx) => ctx.take_function_coverage_map(),
None => return,
let mut mapgen = CoverageMapGenerator::new();
// Encode coverage mappings and generate function records
- let mut function_records = Vec::<&'ll llvm::Value>::new();
- let coverage_mappings_buffer = llvm::build_byte_buffer(|coverage_mappings_buffer| {
- for (instance, function_coverage) in function_coverage_map.into_iter() {
- debug!("Generate coverage map for: {:?}", instance);
-
- let mangled_function_name = cx.tcx.symbol_name(instance).to_string();
- let function_source_hash = function_coverage.source_hash();
- let (expressions, counter_regions) =
- function_coverage.get_expressions_and_counter_regions();
-
- let old_len = coverage_mappings_buffer.len();
- mapgen.write_coverage_mappings(expressions, counter_regions, coverage_mappings_buffer);
- let mapping_data_size = coverage_mappings_buffer.len() - old_len;
- debug_assert!(
- mapping_data_size > 0,
- "Every `FunctionCoverage` should have at least one counter"
- );
-
- let function_record = mapgen.make_function_record(
- cx,
- mangled_function_name,
- function_source_hash,
- mapping_data_size,
- );
- function_records.push(function_record);
- }
- });
+ let mut function_data = Vec::new();
+ for (instance, function_coverage) in function_coverage_map {
+ debug!("Generate coverage map for: {:?}", instance);
+
+ let mangled_function_name = cx.tcx.symbol_name(instance).to_string();
+ let function_source_hash = function_coverage.source_hash();
+ let (expressions, counter_regions) =
+ function_coverage.get_expressions_and_counter_regions();
+
+ let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| {
+ mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
+ });
+ debug_assert!(
+ coverage_mapping_buffer.len() > 0,
+ "Every `FunctionCoverage` should have at least one counter"
+ );
+
+ function_data.push((mangled_function_name, function_source_hash, coverage_mapping_buffer));
+ }
// Encode all filenames referenced by counters/expressions in this module
let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer);
});
+ let filenames_size = filenames_buffer.len();
+ let filenames_val = cx.const_bytes(&filenames_buffer[..]);
+ let filenames_ref = coverageinfo::hash_bytes(filenames_buffer);
+
// Generate the LLVM IR representation of the coverage map and store it in a well-known global
- mapgen.save_generated_coverage_map(
- cx,
- function_records,
- filenames_buffer,
- coverage_mappings_buffer,
- );
+ let cov_data_val = mapgen.generate_coverage_map(cx, version, filenames_size, filenames_val);
+
+ for (mangled_function_name, function_source_hash, coverage_mapping_buffer) in function_data {
+ save_function_record(
+ cx,
+ mangled_function_name,
+ function_source_hash,
+ filenames_ref,
+ coverage_mapping_buffer,
+ );
+ }
+
+ // Save the coverage data value to LLVM IR
+ coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
}
struct CoverageMapGenerator {
/// Using the `expressions` and `counter_regions` collected for the current function, generate
/// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
/// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
- /// the given `coverage_mappings` byte buffer, compliant with the LLVM Coverage Mapping format.
- fn write_coverage_mappings(
+ /// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
+ fn write_coverage_mapping(
&mut self,
expressions: Vec<CounterExpression>,
counter_regions: impl Iterator<Item = (Counter, &'a CodeRegion)>,
- coverage_mappings_buffer: &RustString,
+ coverage_mapping_buffer: &RustString,
) {
let mut counter_regions = counter_regions.collect::<Vec<_>>();
if counter_regions.is_empty() {
virtual_file_mapping,
expressions,
mapping_regions,
- coverage_mappings_buffer,
+ coverage_mapping_buffer,
);
}
- /// Generate and return the function record `Value`
- fn make_function_record(
- &mut self,
- cx: &CodegenCx<'ll, 'tcx>,
- mangled_function_name: String,
- function_source_hash: u64,
- mapping_data_size: usize,
- ) -> &'ll llvm::Value {
- let name_ref = coverageinfo::compute_hash(&mangled_function_name);
- let name_ref_val = cx.const_u64(name_ref);
- let mapping_data_size_val = cx.const_u32(mapping_data_size as u32);
- let func_hash_val = cx.const_u64(function_source_hash);
- cx.const_struct(
- &[name_ref_val, mapping_data_size_val, func_hash_val],
- /*packed=*/ true,
- )
- }
-
- /// Combine the filenames and coverage mappings buffers, construct coverage map header and the
- /// array of function records, and combine everything into the complete coverage map. Save the
- /// coverage map data into the LLVM IR as a static global using a specific, well-known section
- /// and name.
- fn save_generated_coverage_map(
+ /// Construct coverage map header and the array of function records, and combine them into the
+ /// coverage map. Save the coverage map data into the LLVM IR as a static global using a
+ /// specific, well-known section and name.
+ fn generate_coverage_map(
self,
cx: &CodegenCx<'ll, 'tcx>,
- function_records: Vec<&'ll llvm::Value>,
- filenames_buffer: Vec<u8>,
- mut coverage_mappings_buffer: Vec<u8>,
- ) {
- // Concatenate the encoded filenames and encoded coverage mappings, and add additional zero
- // bytes as-needed to ensure 8-byte alignment.
- let mut coverage_size = coverage_mappings_buffer.len();
- let filenames_size = filenames_buffer.len();
- let remaining_bytes =
- (filenames_size + coverage_size) % coverageinfo::COVMAP_VAR_ALIGN_BYTES;
- if remaining_bytes > 0 {
- let pad = coverageinfo::COVMAP_VAR_ALIGN_BYTES - remaining_bytes;
- coverage_mappings_buffer.append(&mut [0].repeat(pad));
- coverage_size += pad;
- }
- let filenames_and_coverage_mappings = [filenames_buffer, coverage_mappings_buffer].concat();
- let filenames_and_coverage_mappings_val =
- cx.const_bytes(&filenames_and_coverage_mappings[..]);
-
- debug!(
- "cov map: n_records = {}, filenames_size = {}, coverage_size = {}, 0-based version = {}",
- function_records.len(),
- filenames_size,
- coverage_size,
- coverageinfo::mapping_version()
- );
+ version: u32,
+ filenames_size: usize,
+ filenames_val: &'ll llvm::Value,
+ ) -> &'ll llvm::Value {
+ debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
- // Create the coverage data header
- let n_records_val = cx.const_u32(function_records.len() as u32);
+ // Create the coverage data header (Note, fields 0 and 2 are now always zero,
+ // as of `llvm::coverage::CovMapVersion::Version4`.)
+ let zero_was_n_records_val = cx.const_u32(0);
let filenames_size_val = cx.const_u32(filenames_size as u32);
- let coverage_size_val = cx.const_u32(coverage_size as u32);
- let version_val = cx.const_u32(coverageinfo::mapping_version());
+ let zero_was_coverage_size_val = cx.const_u32(0);
+ let version_val = cx.const_u32(version);
let cov_data_header_val = cx.const_struct(
- &[n_records_val, filenames_size_val, coverage_size_val, version_val],
+ &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
/*packed=*/ false,
);
- // Create the function records array
- let name_ref_from_u64 = cx.type_i64();
- let mapping_data_size_from_u32 = cx.type_i32();
- let func_hash_from_u64 = cx.type_i64();
- let function_record_ty = cx.type_struct(
- &[name_ref_from_u64, mapping_data_size_from_u32, func_hash_from_u64],
- /*packed=*/ true,
- );
- let function_records_val = cx.const_array(function_record_ty, &function_records[..]);
-
// Create the complete LLVM coverage data value to add to the LLVM IR
- let cov_data_val = cx.const_struct(
- &[cov_data_header_val, function_records_val, filenames_and_coverage_mappings_val],
- /*packed=*/ false,
- );
-
- // Save the coverage data value to LLVM IR
- coverageinfo::save_map_to_mod(cx, cov_data_val);
+ cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
}
}
+
+/// Construct a function record and combine it with the function's coverage mapping data.
+/// Save the function record into the LLVM IR as a static global using a
+/// specific, well-known section and name.
+fn save_function_record(
+ cx: &CodegenCx<'ll, 'tcx>,
+ mangled_function_name: String,
+ function_source_hash: u64,
+ filenames_ref: u64,
+ coverage_mapping_buffer: Vec<u8>,
+) {
+ // Concatenate the encoded coverage mappings
+ let coverage_mapping_size = coverage_mapping_buffer.len();
+ let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer[..]);
+
+ let func_name_hash = coverageinfo::hash_str(&mangled_function_name);
+ let func_name_hash_val = cx.const_u64(func_name_hash);
+ let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32);
+ let func_hash_val = cx.const_u64(function_source_hash);
+ let filenames_ref_val = cx.const_u64(filenames_ref);
+ let func_record_val = cx.const_struct(
+ &[
+ func_name_hash_val,
+ coverage_mapping_size_val,
+ func_hash_val,
+ filenames_ref_val,
+ coverage_mapping_val,
+ ],
+ /*packed=*/ true,
+ );
+
+ // At the present time, the coverage map for Rust assumes every instrumented function `is_used`.
+ // Note that Clang marks functions as "unused" in `CodeGenPGO::emitEmptyCounterMapping`. (See:
+ // https://github.com/rust-lang/llvm-project/blob/de02a75e398415bad4df27b4547c25b896c8bf3b/clang%2Flib%2FCodeGen%2FCodeGenPGO.cpp#L877-L878
+ // for example.)
+ //
+ // It's not yet clear if or how this may be applied to Rust in the future, but the `is_used`
+ // argument is available and handled similarly.
+ let is_used = true;
+ coverageinfo::save_func_record_to_mod(cx, func_name_hash, func_record_val, is_used);
+}
pub mod mapgen;
-const COVMAP_VAR_ALIGN_BYTES: usize = 8;
+const VAR_ALIGN_BYTES: usize = 8;
/// A context object for maintaining all state needed by the coverageinfo module.
pub struct CrateCoverageContext<'tcx> {
);
}
}
+pub(crate) fn hash_str(strval: &str) -> u64 {
+ let strval = CString::new(strval).expect("null error converting hashable str to C string");
+ unsafe { llvm::LLVMRustCoverageHashCString(strval.as_ptr()) }
+}
-pub(crate) fn compute_hash(name: &str) -> u64 {
- let name = CString::new(name).expect("null error converting hashable name to C string");
- unsafe { llvm::LLVMRustCoverageComputeHash(name.as_ptr()) }
+pub(crate) fn hash_bytes(bytes: Vec<u8>) -> u64 {
+ unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) }
}
pub(crate) fn mapping_version() -> u32 {
unsafe { llvm::LLVMRustCoverageMappingVersion() }
}
-pub(crate) fn save_map_to_mod<'ll, 'tcx>(
+pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
cov_data_val: &'ll llvm::Value,
) {
debug!("covmap var name: {:?}", covmap_var_name);
let covmap_section_name = llvm::build_string(|s| unsafe {
- llvm::LLVMRustCoverageWriteSectionNameToString(cx.llmod, s);
+ llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
})
.expect("Rust Coverage section name failed UTF-8 conversion");
debug!("covmap section name: {:?}", covmap_section_name);
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
llvm::set_initializer(llglobal, cov_data_val);
llvm::set_global_constant(llglobal, true);
- llvm::set_linkage(llglobal, llvm::Linkage::InternalLinkage);
+ llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
llvm::set_section(llglobal, &covmap_section_name);
- llvm::set_alignment(llglobal, COVMAP_VAR_ALIGN_BYTES);
+ llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
+ cx.add_used_global(llglobal);
+}
+
+pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ func_name_hash: u64,
+ func_record_val: &'ll llvm::Value,
+ is_used: bool,
+) {
+ // Assign a name to the function record. This is used to merge duplicates.
+ //
+ // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
+ // are included-but-not-used. If (or when) Rust generates functions that are
+ // included-but-not-used, note that a dummy description for a function included-but-not-used
+ // in a Crate can be replaced by full description provided by a different Crate. The two kinds
+ // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
+ // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
+ let func_record_var_name =
+ format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" });
+ debug!("function record var name: {:?}", func_record_var_name);
+
+ let func_record_section_name = llvm::build_string(|s| unsafe {
+ llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
+ })
+ .expect("Rust Coverage function record section name failed UTF-8 conversion");
+ debug!("function record section name: {:?}", func_record_section_name);
+
+ let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
+ llvm::set_initializer(llglobal, func_record_val);
+ llvm::set_global_constant(llglobal, true);
+ llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
+ llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
+ llvm::set_section(llglobal, &func_record_section_name);
+ llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
+ llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
cx.add_used_global(llglobal);
}
self.size.bits(),
self.align.bits() as u32,
self.offset.bits(),
- match self.discriminant {
- None => None,
- Some(value) => Some(cx.const_u64(value)),
- },
+ self.discriminant.map(|v| cx.const_u64(v)),
self.flags,
self.type_metadata,
)
pub mod coverageinfo {
use super::coverage_map;
- /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L205-L221)
+ /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum RegionKind {
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
/// coverage map, in accordance with the
- /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+ /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
/// array", encoded separately), and source location (start and end positions of the represented
/// code region).
///
- /// Aligns with [llvm::coverage::CounterMappingRegion](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L223-L226)
+ /// Aligns with [llvm::coverage::CounterMappingRegion](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L224-L227)
/// Important: The Rust struct layout (order and types of fields) must match its C++
/// counterpart.
#[derive(Copy, Clone, Debug)]
pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &'a Value, FuncName: *const c_char)
-> &'a Value;
- pub fn LLVMRustCoverageComputeHash(Name: *const c_char) -> u64;
+ pub fn LLVMRustCoverageHashCString(StrVal: *const c_char) -> u64;
+ pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
#[allow(improper_ctypes)]
- pub fn LLVMRustCoverageWriteSectionNameToString(M: &Module, Str: &RustString);
+ pub fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString);
+
+ #[allow(improper_ctypes)]
+ pub fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString);
#[allow(improper_ctypes)]
pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
}
}
+pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
+ unsafe {
+ LLVMRustSetVisibility(llglobal, visibility);
+ }
+}
+
pub fn set_alignment(llglobal: &Value, bytes: usize) {
unsafe {
ffi::LLVMSetAlignment(llglobal, bytes as c_uint);
}
}
+pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &str) {
+ unsafe {
+ LLVMRustSetComdat(llmod, llglobal, name.as_ptr().cast(), name.len());
+ }
+}
+
/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
pub fn get_param(llfn: &Value, index: c_uint) -> &Value {
unsafe {
("aarch64", "tvos") => "appletvos",
("x86_64", "tvos") => "appletvsimulator",
("arm", "ios") => "iphoneos",
+ ("aarch64", "ios") if llvm_target.contains("macabi") => "macosx",
("aarch64", "ios") => "iphoneos",
("x86", "ios") => "iphonesimulator",
- ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx10.15",
+ ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx",
("x86_64", "ios") => "iphonesimulator",
_ => {
sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
-/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L91)
+/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum CounterKind {
/// `instrprof.increment()`)
/// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of
/// counter expressions.
-/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L98-L99)
+/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L99-L100)
/// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
}
}
-/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146)
+/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum ExprKind {
Add = 1,
}
-/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147-L148)
+/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L148-L149)
/// Important: The Rust struct layout (order and types of fields) must match its C++
/// counterpart.
#[derive(Copy, Clone, Debug)]
/// `funclet_bb` member if it is not `None`.
fn funclet<'b, Bx: BuilderMethods<'a, 'tcx>>(
&self,
- fx: &'b mut FunctionCx<'a, 'tcx, Bx>,
+ fx: &'b FunctionCx<'a, 'tcx, Bx>,
) -> Option<&'b Bx::Funclet> {
- match self.funclet_bb {
- Some(funcl) => fx.funclets[funcl].as_ref(),
- None => None,
- }
+ self.funclet_bb.and_then(|funcl| fx.funclets[funcl].as_ref())
}
fn lltarget<Bx: BuilderMethods<'a, 'tcx>>(
return;
}
let llval = match self.fn_abi.ret.mode {
- PassMode::Ignore | PassMode::Indirect(..) => {
+ PassMode::Ignore | PassMode::Indirect { .. } => {
bx.ret_void();
return;
}
Inhabited,
ZeroValid,
UninitValid,
- };
+ }
let panic_intrinsic = intrinsic.and_then(|i| match i {
sym::assert_inhabited => Some(AssertIntrinsic::Inhabited),
sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid),
// Force by-ref if we have to load through a cast pointer.
let (mut llval, align, by_ref) = match op.val {
Immediate(_) | Pair(..) => match arg.mode {
- PassMode::Indirect(..) | PassMode::Cast(_) => {
+ PassMode::Indirect { .. } | PassMode::Cast(_) => {
let scratch = PlaceRef::alloca(bx, arg.layout);
op.val.store(bx, scratch);
(scratch.llval, scratch.align, true)
panic!("Cannot decode `Fingerprint` with `{}`", std::any::type_name::<D>());
}
}
+
impl FingerprintDecoder for opaque::Decoder<'_> {
fn decode_fingerprint(&mut self) -> Result<Fingerprint, String> {
Fingerprint::decode_opaque(self)
}
}
+
+// `PackedFingerprint` wraps a `Fingerprint`. Its purpose is to, on certain
+// architectures, behave like a `Fingerprint` without alignment requirements.
+// This behavior is only enabled on x86 and x86_64, where the impact of
+// unaligned accesses is tolerable in small doses.
+//
+// This may be preferable to use in large collections of structs containing
+// fingerprints, as it can reduce memory consumption by preventing the padding
+// that the more strictly-aligned `Fingerprint` can introduce. An application of
+// this is in the query dependency graph, which contains a large collection of
+// `DepNode`s. As of this writing, the size of a `DepNode` decreases by ~30%
+// (from 24 bytes to 17) by using the packed representation here, which
+// noticeably decreases total memory usage when compiling large crates.
+//
+// The wrapped `Fingerprint` is private to reduce the chance of a client
+// invoking undefined behavior by taking a reference to the packed field.
+#[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed))]
+#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)]
+pub struct PackedFingerprint(Fingerprint);
+
+impl std::fmt::Display for PackedFingerprint {
+ #[inline]
+ fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ // Copy to avoid taking reference to packed field.
+ let copy = self.0;
+ copy.fmt(formatter)
+ }
+}
+
+impl<E: rustc_serialize::Encoder> Encodable<E> for PackedFingerprint {
+ #[inline]
+ fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+ // Copy to avoid taking reference to packed field.
+ let copy = self.0;
+ copy.encode(s)
+ }
+}
+
+impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint {
+ #[inline]
+ fn decode(d: &mut D) -> Result<Self, D::Error> {
+ Fingerprint::decode(d).map(|f| PackedFingerprint(f))
+ }
+}
+
+impl From<Fingerprint> for PackedFingerprint {
+ #[inline]
+ fn from(f: Fingerprint) -> PackedFingerprint {
+ PackedFingerprint(f)
+ }
+}
+
+impl From<PackedFingerprint> for Fingerprint {
+ #[inline]
+ fn from(f: PackedFingerprint) -> Fingerprint {
+ f.0
+ }
+}
let scc_indices = (0..num_nodes)
.map(G::Node::new)
- .map(|node| match this.walk_node(0, node) {
+ .map(|node| match this.start_walk_from(node) {
WalkReturn::Complete { scc_index } => scc_index,
- WalkReturn::Cycle { min_depth } => {
- panic!("`walk_node(0, {:?})` returned cycle with depth {:?}", node, min_depth)
- }
+ WalkReturn::Cycle { min_depth } => panic!(
+ "`start_walk_node({:?})` returned cycle with depth {:?}",
+ node, min_depth
+ ),
})
.collect();
Sccs { scc_indices, scc_data: this.scc_data }
}
- /// Visits a node during the DFS. We first examine its current
- /// state -- if it is not yet visited (`NotVisited`), we can push
- /// it onto the stack and start walking its successors.
+ fn start_walk_from(&mut self, node: G::Node) -> WalkReturn<S> {
+ if let Some(result) = self.inspect_node(node) {
+ result
+ } else {
+ self.walk_unvisited_node(node)
+ }
+ }
+
+ /// Inspect a node during the DFS. We first examine its current
+ /// state -- if it is not yet visited (`NotVisited`), return `None` so
+ /// that the caller might push it onto the stack and start walking its
+ /// successors.
///
/// If it is already on the DFS stack it will be in the state
/// `BeingVisited`. In that case, we have found a cycle and we
/// Otherwise, we are looking at a node that has already been
/// completely visited. We therefore return `WalkReturn::Complete`
/// with its associated SCC index.
- fn walk_node(&mut self, depth: usize, node: G::Node) -> WalkReturn<S> {
- debug!("walk_node(depth = {:?}, node = {:?})", depth, node);
- match self.find_state(node) {
+ fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<S>> {
+ Some(match self.find_state(node) {
NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index },
NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth },
- NodeState::NotVisited => self.walk_unvisited_node(depth, node),
+ NodeState::NotVisited => return None,
NodeState::InCycleWith { parent } => panic!(
"`find_state` returned `InCycleWith({:?})`, which ought to be impossible",
parent
),
- }
+ })
}
/// Fetches the state of the node `r`. If `r` is recorded as being
/// of `r2` (and updates `r` to reflect current result). This is
/// basically the "find" part of a standard union-find algorithm
/// (with path compression).
- fn find_state(&mut self, r: G::Node) -> NodeState<G::Node, S> {
- debug!("find_state(r = {:?} in state {:?})", r, self.node_states[r]);
- match self.node_states[r] {
- NodeState::InCycle { scc_index } => NodeState::InCycle { scc_index },
- NodeState::BeingVisited { depth } => NodeState::BeingVisited { depth },
- NodeState::NotVisited => NodeState::NotVisited,
- NodeState::InCycleWith { parent } => {
- let parent_state = self.find_state(parent);
- debug!("find_state: parent_state = {:?}", parent_state);
- match parent_state {
- NodeState::InCycle { .. } => {
- self.node_states[r] = parent_state;
- parent_state
- }
+ fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, S> {
+ // To avoid recursion we temporarily reuse the `parent` of each
+ // InCycleWith link to encode a downwards link while compressing
+ // the path. After we have found the root or deepest node being
+ // visited, we traverse the reverse links and correct the node
+ // states on the way.
+ //
+ // **Note**: This mutation requires that this is a leaf function
+ // or at least that none of the called functions inspects the
+ // current node states. Luckily, we are a leaf.
+
+ // Remember one previous link. The termination condition when
+ // following links downwards is then simply as soon as we have
+ // found the initial self-loop.
+ let mut previous_node = node;
+
+ // Ultimately assigned by the parent when following
+ // `InCycleWith` upwards.
+ let node_state = loop {
+ debug!("find_state(r = {:?} in state {:?})", node, self.node_states[node]);
+ match self.node_states[node] {
+ NodeState::InCycle { scc_index } => break NodeState::InCycle { scc_index },
+ NodeState::BeingVisited { depth } => break NodeState::BeingVisited { depth },
+ NodeState::NotVisited => break NodeState::NotVisited,
+ NodeState::InCycleWith { parent } => {
+ // We test this, to be extremely sure that we never
+ // ever break our termination condition for the
+ // reverse iteration loop.
+ assert!(node != parent, "Node can not be in cycle with itself");
+ // Store the previous node as an inverted list link
+ self.node_states[node] = NodeState::InCycleWith { parent: previous_node };
+ // Update to parent node.
+ previous_node = node;
+ node = parent;
+ }
+ }
+ };
- NodeState::BeingVisited { depth } => {
- self.node_states[r] =
- NodeState::InCycleWith { parent: self.node_stack[depth] };
- parent_state
- }
+ // The states form a graph where up to one outgoing link is stored at
+ // each node. Initially in general,
+ //
+ // E
+ // ^
+ // |
+ // InCycleWith/BeingVisited/NotVisited
+ // |
+ // A-InCycleWith->B-InCycleWith…>C-InCycleWith->D-+
+ // |
+ // = node, previous_node
+ //
+ // After the first loop, this will look like
+ // E
+ // ^
+ // |
+ // InCycleWith/BeingVisited/NotVisited
+ // |
+ // +>A<-InCycleWith-B<…InCycleWith-C<-InCycleWith-D-+
+ // | | | |
+ // | InCycleWith | = node
+ // +-+ =previous_node
+ //
+ // Note in particular that A will be linked to itself in a self-cycle
+ // and no other self-cycles occur due to how InCycleWith is assigned in
+ // the find phase implemented by `walk_unvisited_node`.
+ //
+ // We now want to compress the path, that is assign the state of the
+ // link D-E to all other links.
+ //
+ // We can then walk backwards, starting from `previous_node`, and assign
+ // each node in the list with the updated state. The loop terminates
+ // when we reach the self-cycle.
+
+ // Move backwards until we found the node where we started. We
+ // will know when we hit the state where previous_node == node.
+ loop {
+ // Back at the beginning, we can return.
+ if previous_node == node {
+ return node_state;
+ }
+ // Update to previous node in the link.
+ match self.node_states[previous_node] {
+ NodeState::InCycleWith { parent: previous } => {
+ node = previous_node;
+ previous_node = previous;
+ }
+ // Only InCycleWith nodes were added to the reverse linked list.
+ other => panic!("Invalid previous link while compressing cycle: {:?}", other),
+ }
- NodeState::NotVisited | NodeState::InCycleWith { .. } => {
- panic!("invalid parent state: {:?}", parent_state)
- }
+ debug!("find_state: parent_state = {:?}", node_state);
+
+ // Update the node state from the parent state. The assigned
+ // state is actually a loop invariant but it will only be
+ // evaluated if there is at least one backlink to follow.
+ // Fully trusting llvm here to find this loop optimization.
+ match node_state {
+ // Path compression, make current node point to the same root.
+ NodeState::InCycle { .. } => {
+ self.node_states[node] = node_state;
+ }
+ // Still visiting nodes, compress to cycle to the node
+ // at that depth.
+ NodeState::BeingVisited { depth } => {
+ self.node_states[node] =
+ NodeState::InCycleWith { parent: self.node_stack[depth] };
+ }
+ // These are never allowed as parent nodes. InCycleWith
+ // should have been followed to a real parent and
+ // NotVisited can not be part of a cycle since it should
+ // have instead gotten explored.
+ NodeState::NotVisited | NodeState::InCycleWith { .. } => {
+ panic!("invalid parent state: {:?}", node_state)
}
}
}
}
/// Walks a node that has never been visited before.
- fn walk_unvisited_node(&mut self, depth: usize, node: G::Node) -> WalkReturn<S> {
- debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node);
-
- debug_assert!(matches!(self.node_states[node], NodeState::NotVisited));
-
- // Push `node` onto the stack.
- self.node_states[node] = NodeState::BeingVisited { depth };
- self.node_stack.push(node);
-
- // Walk each successor of the node, looking to see if any of
- // them can reach a node that is presently on the stack. If
- // so, that means they can also reach us.
- let mut min_depth = depth;
- let mut min_cycle_root = node;
- let successors_len = self.successors_stack.len();
- for successor_node in self.graph.successors(node) {
- debug!("walk_unvisited_node: node = {:?} successor_ode = {:?}", node, successor_node);
- match self.walk_node(depth + 1, successor_node) {
- WalkReturn::Cycle { min_depth: successor_min_depth } => {
- // Track the minimum depth we can reach.
- assert!(successor_min_depth <= depth);
- if successor_min_depth < min_depth {
+ ///
+ /// Call this method when `inspect_node` has returned `None`. Having the
+ /// caller decide avoids mutual recursion between the two methods and allows
+ /// us to maintain an allocated stack for nodes on the path between calls.
+ fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<S> {
+ struct VisitingNodeFrame<G: DirectedGraph, Successors> {
+ node: G::Node,
+ iter: Option<Successors>,
+ depth: usize,
+ min_depth: usize,
+ successors_len: usize,
+ min_cycle_root: G::Node,
+ successor_node: G::Node,
+ }
+
+ // Move the stack to a local variable. We want to utilize the existing allocation and
+ // mutably borrow it without borrowing self at the same time.
+ let mut successors_stack = core::mem::take(&mut self.successors_stack);
+ debug_assert_eq!(successors_stack.len(), 0);
+
+ let mut stack: Vec<VisitingNodeFrame<G, _>> = vec![VisitingNodeFrame {
+ node: initial,
+ depth: 0,
+ min_depth: 0,
+ iter: None,
+ successors_len: 0,
+ min_cycle_root: initial,
+ successor_node: initial,
+ }];
+
+ let mut return_value = None;
+
+ 'recurse: while let Some(frame) = stack.last_mut() {
+ let VisitingNodeFrame {
+ node,
+ depth,
+ iter,
+ successors_len,
+ min_depth,
+ min_cycle_root,
+ successor_node,
+ } = frame;
+
+ let node = *node;
+ let depth = *depth;
+
+ let successors = match iter {
+ Some(iter) => iter,
+ None => {
+ // This None marks that we still have the initialize this node's frame.
+ debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node);
+
+ debug_assert!(matches!(self.node_states[node], NodeState::NotVisited));
+
+ // Push `node` onto the stack.
+ self.node_states[node] = NodeState::BeingVisited { depth };
+ self.node_stack.push(node);
+
+ // Walk each successor of the node, looking to see if any of
+ // them can reach a node that is presently on the stack. If
+ // so, that means they can also reach us.
+ *successors_len = successors_stack.len();
+ // Set and return a reference, this is currently empty.
+ iter.get_or_insert(self.graph.successors(node))
+ }
+ };
+
+ // Now that iter is initialized, this is a constant for this frame.
+ let successors_len = *successors_len;
+
+ // Construct iterators for the nodes and walk results. There are two cases:
+ // * The walk of a successor node returned.
+ // * The remaining successor nodes.
+ let returned_walk =
+ return_value.take().into_iter().map(|walk| (*successor_node, Some(walk)));
+
+ let successor_walk = successors.by_ref().map(|successor_node| {
+ debug!(
+ "walk_unvisited_node: node = {:?} successor_ode = {:?}",
+ node, successor_node
+ );
+ (successor_node, self.inspect_node(successor_node))
+ });
+
+ for (successor_node, walk) in returned_walk.chain(successor_walk) {
+ match walk {
+ Some(WalkReturn::Cycle { min_depth: successor_min_depth }) => {
+ // Track the minimum depth we can reach.
+ assert!(successor_min_depth <= depth);
+ if successor_min_depth < *min_depth {
+ debug!(
+ "walk_unvisited_node: node = {:?} successor_min_depth = {:?}",
+ node, successor_min_depth
+ );
+ *min_depth = successor_min_depth;
+ *min_cycle_root = successor_node;
+ }
+ }
+
+ Some(WalkReturn::Complete { scc_index: successor_scc_index }) => {
+ // Push the completed SCC indices onto
+ // the `successors_stack` for later.
debug!(
- "walk_unvisited_node: node = {:?} successor_min_depth = {:?}",
- node, successor_min_depth
+ "walk_unvisited_node: node = {:?} successor_scc_index = {:?}",
+ node, successor_scc_index
);
- min_depth = successor_min_depth;
- min_cycle_root = successor_node;
+ successors_stack.push(successor_scc_index);
}
- }
- WalkReturn::Complete { scc_index: successor_scc_index } => {
- // Push the completed SCC indices onto
- // the `successors_stack` for later.
- debug!(
- "walk_unvisited_node: node = {:?} successor_scc_index = {:?}",
- node, successor_scc_index
- );
- self.successors_stack.push(successor_scc_index);
+ None => {
+ let depth = depth + 1;
+ debug!("walk_node(depth = {:?}, node = {:?})", depth, successor_node);
+ // Remember which node the return value will come from.
+ frame.successor_node = successor_node;
+ // Start a new stack frame the step into it.
+ stack.push(VisitingNodeFrame {
+ node: successor_node,
+ depth,
+ iter: None,
+ successors_len: 0,
+ min_depth: depth,
+ min_cycle_root: successor_node,
+ successor_node: successor_node,
+ });
+ continue 'recurse;
+ }
}
}
- }
- // Completed walk, remove `node` from the stack.
- let r = self.node_stack.pop();
- debug_assert_eq!(r, Some(node));
-
- // If `min_depth == depth`, then we are the root of the
- // cycle: we can't reach anyone further down the stack.
- if min_depth == depth {
- // Note that successor stack may have duplicates, so we
- // want to remove those:
- let deduplicated_successors = {
- let duplicate_set = &mut self.duplicate_set;
- duplicate_set.clear();
- self.successors_stack
- .drain(successors_len..)
- .filter(move |&i| duplicate_set.insert(i))
- };
- let scc_index = self.scc_data.create_scc(deduplicated_successors);
- self.node_states[node] = NodeState::InCycle { scc_index };
- WalkReturn::Complete { scc_index }
- } else {
- // We are not the head of the cycle. Return back to our
- // caller. They will take ownership of the
- // `self.successors` data that we pushed.
- self.node_states[node] = NodeState::InCycleWith { parent: min_cycle_root };
- WalkReturn::Cycle { min_depth }
+ // Completed walk, remove `node` from the stack.
+ let r = self.node_stack.pop();
+ debug_assert_eq!(r, Some(node));
+
+ // Remove the frame, it's done.
+ let frame = stack.pop().unwrap();
+
+ // If `min_depth == depth`, then we are the root of the
+ // cycle: we can't reach anyone further down the stack.
+
+ // Pass the 'return value' down the stack.
+ // We return one frame at a time so there can't be another return value.
+ debug_assert!(return_value.is_none());
+ return_value = Some(if frame.min_depth == depth {
+ // Note that successor stack may have duplicates, so we
+ // want to remove those:
+ let deduplicated_successors = {
+ let duplicate_set = &mut self.duplicate_set;
+ duplicate_set.clear();
+ successors_stack
+ .drain(successors_len..)
+ .filter(move |&i| duplicate_set.insert(i))
+ };
+ let scc_index = self.scc_data.create_scc(deduplicated_successors);
+ self.node_states[node] = NodeState::InCycle { scc_index };
+ WalkReturn::Complete { scc_index }
+ } else {
+ // We are not the head of the cycle. Return back to our
+ // caller. They will take ownership of the
+ // `self.successors` data that we pushed.
+ self.node_states[node] = NodeState::InCycleWith { parent: frame.min_cycle_root };
+ WalkReturn::Cycle { min_depth: frame.min_depth }
+ });
}
+
+ // Keep the allocation we used for successors_stack.
+ self.successors_stack = successors_stack;
+ debug_assert_eq!(self.successors_stack.len(), 0);
+
+ return_value.unwrap()
}
}
+extern crate test;
+
use super::*;
use crate::graph::tests::TestGraph;
assert_eq!(sccs.successors(0), &[]);
assert_eq!(sccs.successors(1), &[0]);
}
+
+#[test]
+fn test_deep_linear() {
+ /*
+ 0
+ |
+ v
+ 1
+ |
+ v
+ 2
+ |
+ v
+ …
+ */
+ const NR_NODES: usize = 1 << 14;
+ let mut nodes = vec![];
+ for i in 1..NR_NODES {
+ nodes.push((i - 1, i));
+ }
+ let graph = TestGraph::new(0, nodes.as_slice());
+ let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ assert_eq!(sccs.num_sccs(), NR_NODES);
+ assert_eq!(sccs.scc(0), NR_NODES - 1);
+ assert_eq!(sccs.scc(NR_NODES - 1), 0);
+}
+
+#[bench]
+fn bench_sccc(b: &mut test::Bencher) {
+ // Like `test_three_sccs` but each state is replaced by a group of
+ // three or four to have some amount of test data.
+ /*
+ 0-3
+ |
+ v
+ +->4-6 11-14
+ | | |
+ | v |
+ +--7-10<-+
+ */
+ fn make_3_clique(slice: &mut [(usize, usize)], base: usize) {
+ slice[0] = (base + 0, base + 1);
+ slice[1] = (base + 1, base + 2);
+ slice[2] = (base + 2, base + 0);
+ }
+ // Not actually a clique but strongly connected.
+ fn make_4_clique(slice: &mut [(usize, usize)], base: usize) {
+ slice[0] = (base + 0, base + 1);
+ slice[1] = (base + 1, base + 2);
+ slice[2] = (base + 2, base + 3);
+ slice[3] = (base + 3, base + 0);
+ slice[4] = (base + 1, base + 3);
+ slice[5] = (base + 2, base + 1);
+ }
+
+ let mut graph = [(0, 0); 6 + 3 + 6 + 3 + 4];
+ make_4_clique(&mut graph[0..6], 0);
+ make_3_clique(&mut graph[6..9], 4);
+ make_4_clique(&mut graph[9..15], 7);
+ make_3_clique(&mut graph[15..18], 11);
+ graph[18] = (0, 4);
+ graph[19] = (5, 7);
+ graph[20] = (11, 10);
+ graph[21] = (7, 4);
+ let graph = TestGraph::new(0, &graph[..]);
+ b.iter(|| {
+ let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ assert_eq!(sccs.num_sccs(), 3);
+ });
+}
#![feature(fn_traits)]
#![feature(int_bits_const)]
#![feature(min_specialization)]
-#![feature(optin_builtin_traits)]
+#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
+#![cfg_attr(not(bootstrap), feature(auto_traits))]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
#![feature(once_cell)]
#![feature(maybe_uninit_uninit_array)]
#![allow(rustc::default_hash_types)]
+#![deny(unaligned_references)]
#[macro_use]
extern crate tracing;
interface::run_compiler(config, |compiler| {
let sopts = &compiler.session().opts;
if sopts.describe_lints {
- let lint_store = rustc_lint::new_lint_store(
+ let mut lint_store = rustc_lint::new_lint_store(
sopts.debugging_opts.no_interleave_lints,
compiler.session().unstable_options(),
);
- describe_lints(compiler.session(), &lint_store, false);
+ let registered_lints =
+ if let Some(register_lints) = compiler.register_lints() {
+ register_lints(compiler.session(), &mut lint_store);
+ true
+ } else {
+ false
+ };
+ describe_lints(compiler.session(), &lint_store, registered_lints);
return;
}
let should_stop = RustcDefaultCalls::print_crate_info(
match (loaded_plugins, plugin.len(), plugin_groups.len()) {
(false, 0, _) | (false, _, 0) => {
- println!(
- "Compiler plugins can provide additional lints and lint groups. To see a \
- listing of these, re-run `rustc -W help` with a crate filename."
- );
+ println!("Lint tools like Clippy can provide additional lints and lint groups.");
}
(false, ..) => panic!("didn't load lint plugins but got them anyway!"),
(true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
Ok(s) if s.is_empty() => return,
Ok(_) => {}
}
+ let color_logs = match std::env::var(String::from(env) + "_COLOR") {
+ Ok(value) => match value.as_ref() {
+ "always" => true,
+ "never" => false,
+ "auto" => stdout_isatty(),
+ _ => early_error(
+ ErrorOutputType::default(),
+ &format!(
+ "invalid log color value '{}': expected one of always, never, or auto",
+ value
+ ),
+ ),
+ },
+ Err(std::env::VarError::NotPresent) => stdout_isatty(),
+ Err(std::env::VarError::NotUnicode(_value)) => early_error(
+ ErrorOutputType::default(),
+ "non-Unicode log color value: expected one of always, never, or auto",
+ ),
+ };
let filter = tracing_subscriber::EnvFilter::from_env(env);
let layer = tracing_tree::HierarchicalLayer::default()
+ .with_writer(io::stderr)
.with_indent_lines(true)
- .with_ansi(true)
+ .with_ansi(color_logs)
.with_targets(true)
.with_wraparound(10)
.with_verbose_exit(true)
arg.into_string().unwrap_or_else(|arg| {
early_error(
ErrorOutputType::default(),
- &format!("Argument {} is not valid Unicode: {:?}", i, arg),
+ &format!("argument {} is not valid Unicode: {:?}", i, arg),
)
})
})
This will compile:
```ignore (ignore auto_trait future compatibility warning)
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
struct Foo;
Erroneous code example:
```compile_fail,E0321
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
struct Foo;
Erroneous code example:
```compile_fail,E0567
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
auto trait Generic<T> {} // error!
# fn main() {}
To fix this issue, just remove the generics:
```
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
auto trait Generic {} // ok!
# fn main() {}
Erroneous code example:
```compile_fail,E0568
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
auto trait Bound : Copy {} // error!
To fix this issue, just remove the super trait:
```
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
auto trait Bound {} // ok!
pub fn derive_allowed(&self) -> bool {
match *self {
+ Annotatable::Stmt(ref stmt) => match stmt.kind {
+ ast::StmtKind::Item(ref item) => match item.kind {
+ ast::ItemKind::Struct(..)
+ | ast::ItemKind::Enum(..)
+ | ast::ItemKind::Union(..) => true,
+ _ => false,
+ },
+ _ => false,
+ },
Annotatable::Item(ref item) => match item.kind {
ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
true
/// Expansion produced a result (possibly dummy).
Ready(T),
/// Expansion could not produce a result and needs to be retried.
- /// The string is an explanation that will be printed if we are stuck in an infinite retry loop.
- Retry(U, String),
+ Retry(U),
}
// `meta_item` is the attribute, and `item` is the item being modified.
id: ast::DUMMY_NODE_ID,
span: e.span,
kind: ast::StmtKind::Expr(e),
- tokens: None
}]
})
};
id: ast::DUMMY_NODE_ID,
kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)),
span: self.span,
- tokens: None
}])
}
/// Some parent node that is close enough to the given macro call.
fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId;
+ // Resolver interfaces for specific built-in macros.
+ /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
fn has_derive_copy(&self, expn_id: ExpnId) -> bool;
- fn add_derive_copy(&mut self, expn_id: ExpnId);
+ /// Path resolution logic for `#[cfg_accessible(path)]`.
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
}
pub root_path: PathBuf,
pub resolver: &'a mut dyn ResolverExpand,
pub current_expansion: ExpansionData,
+ /// Error recovery mode entered when expansion is stuck
+ /// (or during eager expansion, but that's a hack).
+ pub force_mode: bool,
pub expansions: FxHashMap<Span, Vec<String>>,
/// Called directly after having parsed an external `mod foo;` in expansion.
pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
directory_ownership: DirectoryOwnership::Owned { relative: None },
prior_type_ascription: None,
},
+ force_mode: false,
expansions: FxHashMap::default(),
}
}
}
pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
- ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- span: expr.span,
- kind: ast::StmtKind::Expr(expr),
- tokens: None,
- }
+ ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) }
}
pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt {
id: ast::DUMMY_NODE_ID,
span: sp,
attrs: AttrVec::new(),
- });
- ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- kind: ast::StmtKind::Local(local),
- span: sp,
tokens: None,
- }
+ });
+ ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
}
// Generates `let _: Type;`, which is usually used for type assertions.
id: ast::DUMMY_NODE_ID,
span,
attrs: AttrVec::new(),
+ tokens: None,
});
- ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span, tokens: None }
+ ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
}
pub fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
- ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- kind: ast::StmtKind::Item(item),
- span: sp,
- tokens: None,
- }
+ ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp }
}
pub fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block> {
id: ast::DUMMY_NODE_ID,
span: expr.span,
kind: ast::StmtKind::Expr(expr),
- tokens: None,
}],
)
}
//! Conditional compilation stripping.
+use crate::base::Annotatable;
+
use rustc_ast::attr::HasAttrs;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) {
fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg));
}
+
+ pub fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
+ // Since the item itself has already been configured by the InvocationCollector,
+ // we know that fold result vector will contain exactly one element
+ match item {
+ Annotatable::Item(item) => Annotatable::Item(self.flat_map_item(item).pop().unwrap()),
+ Annotatable::TraitItem(item) => {
+ Annotatable::TraitItem(self.flat_map_trait_item(item).pop().unwrap())
+ }
+ Annotatable::ImplItem(item) => {
+ Annotatable::ImplItem(self.flat_map_impl_item(item).pop().unwrap())
+ }
+ Annotatable::ForeignItem(item) => {
+ Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
+ }
+ Annotatable::Stmt(stmt) => {
+ Annotatable::Stmt(stmt.map(|stmt| self.flat_map_stmt(stmt).pop().unwrap()))
+ }
+ Annotatable::Expr(mut expr) => Annotatable::Expr({
+ self.visit_expr(&mut expr);
+ expr
+ }),
+ Annotatable::Arm(arm) => Annotatable::Arm(self.flat_map_arm(arm).pop().unwrap()),
+ Annotatable::Field(field) => {
+ Annotatable::Field(self.flat_map_field(field).pop().unwrap())
+ }
+ Annotatable::FieldPat(fp) => {
+ Annotatable::FieldPat(self.flat_map_field_pattern(fp).pop().unwrap())
+ }
+ Annotatable::GenericParam(param) => {
+ Annotatable::GenericParam(self.flat_map_generic_param(param).pop().unwrap())
+ }
+ Annotatable::Param(param) => {
+ Annotatable::Param(self.flat_map_param(param).pop().unwrap())
+ }
+ Annotatable::StructField(sf) => {
+ Annotatable::StructField(self.flat_map_struct_field(sf).pop().unwrap())
+ }
+ Annotatable::Variant(v) => {
+ Annotatable::Variant(self.flat_map_variant(v).pop().unwrap())
+ }
+ }
+ }
}
impl<'a> MutVisitor for StripUnconfigured<'a> {
self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
}
+ /// Fragment supports macro expansion and not just inert attributes, `cfg` and `cfg_attr`.
+ pub fn supports_macro_expansion(self) -> bool {
+ match self {
+ AstFragmentKind::OptExpr
+ | AstFragmentKind::Expr
+ | AstFragmentKind::Pat
+ | AstFragmentKind::Ty
+ | AstFragmentKind::Stmts
+ | AstFragmentKind::Items
+ | AstFragmentKind::TraitItems
+ | AstFragmentKind::ImplItems
+ | AstFragmentKind::ForeignItems => true,
+ AstFragmentKind::Arms
+ | AstFragmentKind::Fields
+ | AstFragmentKind::FieldPats
+ | AstFragmentKind::GenericParams
+ | AstFragmentKind::Params
+ | AstFragmentKind::StructFields
+ | AstFragmentKind::Variants => false,
+ }
+ }
+
fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
self,
items: I,
// Recursively expand all macro invocations in this AST fragment.
pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
let orig_expansion_data = self.cx.current_expansion.clone();
+ let orig_force_mode = self.cx.force_mode;
self.cx.current_expansion.depth = 0;
// Collect all macro invocations and replace them with placeholders.
}
invocations = mem::take(&mut undetermined_invocations);
force = !mem::replace(&mut progress, false);
+ if force && self.monotonic {
+ self.cx.sess.delay_span_bug(
+ invocations.last().unwrap().0.span(),
+ "expansion entered force mode without producing any errors",
+ );
+ }
continue;
};
let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;
self.cx.current_expansion = invoc.expansion_data.clone();
+ self.cx.force_mode = force;
// FIXME(jseyfried): Refactor out the following logic
+ let fragment_kind = invoc.fragment_kind;
let (expanded_fragment, new_invocations) = match res {
InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
- ExpandResult::Retry(invoc, explanation) => {
+ ExpandResult::Retry(invoc) => {
if force {
- // We are stuck, stop retrying and produce a dummy fragment.
- let span = invoc.span();
- self.cx.span_err(span, &explanation);
- let fragment = invoc.fragment_kind.dummy(span);
- self.collect_invocations(fragment, &[])
+ self.cx.span_bug(
+ invoc.span(),
+ "expansion entered force mode but is still stuck",
+ );
} else {
// Cannot expand, will retry this invocation later.
undetermined_invocations
InvocationRes::DeriveContainer(_exts) => {
// FIXME: Consider using the derive resolutions (`_exts`) immediately,
// instead of enqueuing the derives to be resolved again later.
- let (derives, item) = match invoc.kind {
+ let (derives, mut item) = match invoc.kind {
InvocationKind::DeriveContainer { derives, item } => (derives, item),
_ => unreachable!(),
};
- if !item.derive_allowed() {
+ let (item, derive_placeholders) = if !item.derive_allowed() {
self.error_derive_forbidden_on_non_adt(&derives, &item);
- }
+ item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+ (item, Vec::new())
+ } else {
+ let mut item = StripUnconfigured {
+ sess: self.cx.sess,
+ features: self.cx.ecfg.features,
+ }
+ .fully_configure(item);
+ item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+
+ invocations.reserve(derives.len());
+ let derive_placeholders = derives
+ .into_iter()
+ .map(|path| {
+ let expn_id = ExpnId::fresh(None);
+ invocations.push((
+ Invocation {
+ kind: InvocationKind::Derive { path, item: item.clone() },
+ fragment_kind,
+ expansion_data: ExpansionData {
+ id: expn_id,
+ ..self.cx.current_expansion.clone()
+ },
+ },
+ None,
+ ));
+ NodeId::placeholder_from_expn_id(expn_id)
+ })
+ .collect::<Vec<_>>();
+ (item, derive_placeholders)
+ };
- let mut item = self.fully_configure(item);
- item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
-
- let mut derive_placeholders = Vec::with_capacity(derives.len());
- invocations.reserve(derives.len());
- for path in derives {
- let expn_id = ExpnId::fresh(None);
- derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
- invocations.push((
- Invocation {
- kind: InvocationKind::Derive { path, item: item.clone() },
- fragment_kind: invoc.fragment_kind,
- expansion_data: ExpansionData {
- id: expn_id,
- ..invoc.expansion_data.clone()
- },
- },
- None,
- ));
- }
- let fragment =
- invoc.fragment_kind.expect_from_annotatables(::std::iter::once(item));
+ let fragment = fragment_kind.expect_from_annotatables(::std::iter::once(item));
self.collect_invocations(fragment, &derive_placeholders)
}
};
}
self.cx.current_expansion = orig_expansion_data;
+ self.cx.force_mode = orig_force_mode;
// Finally incorporate all the expanded macros into the input AST fragment.
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
(fragment, invocations)
}
- fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
- let mut cfg = StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features };
- // Since the item itself has already been configured by the InvocationCollector,
- // we know that fold result vector will contain exactly one element
- match item {
- Annotatable::Item(item) => Annotatable::Item(cfg.flat_map_item(item).pop().unwrap()),
- Annotatable::TraitItem(item) => {
- Annotatable::TraitItem(cfg.flat_map_trait_item(item).pop().unwrap())
- }
- Annotatable::ImplItem(item) => {
- Annotatable::ImplItem(cfg.flat_map_impl_item(item).pop().unwrap())
- }
- Annotatable::ForeignItem(item) => {
- Annotatable::ForeignItem(cfg.flat_map_foreign_item(item).pop().unwrap())
- }
- Annotatable::Stmt(stmt) => {
- Annotatable::Stmt(stmt.map(|stmt| cfg.flat_map_stmt(stmt).pop().unwrap()))
- }
- Annotatable::Expr(mut expr) => Annotatable::Expr({
- cfg.visit_expr(&mut expr);
- expr
- }),
- Annotatable::Arm(arm) => Annotatable::Arm(cfg.flat_map_arm(arm).pop().unwrap()),
- Annotatable::Field(field) => {
- Annotatable::Field(cfg.flat_map_field(field).pop().unwrap())
- }
- Annotatable::FieldPat(fp) => {
- Annotatable::FieldPat(cfg.flat_map_field_pattern(fp).pop().unwrap())
- }
- Annotatable::GenericParam(param) => {
- Annotatable::GenericParam(cfg.flat_map_generic_param(param).pop().unwrap())
- }
- Annotatable::Param(param) => {
- Annotatable::Param(cfg.flat_map_param(param).pop().unwrap())
- }
- Annotatable::StructField(sf) => {
- Annotatable::StructField(cfg.flat_map_struct_field(sf).pop().unwrap())
- }
- Annotatable::Variant(v) => Annotatable::Variant(cfg.flat_map_variant(v).pop().unwrap()),
- }
- }
-
fn error_recursion_limit_reached(&mut self) {
let expn_data = self.cx.current_expansion.id.expn_data();
let suggested_limit = self.cx.ecfg.recursion_limit * 2;
Ok(meta) => {
let items = match expander.expand(self.cx, span, &meta, item) {
ExpandResult::Ready(items) => items,
- ExpandResult::Retry(item, explanation) => {
+ ExpandResult::Retry(item) => {
// Reassemble the original invocation for retrying.
- return ExpandResult::Retry(
- Invocation {
- kind: InvocationKind::Attr {
- attr,
- item,
- derives,
- after_derive,
- },
- ..invoc
+ return ExpandResult::Retry(Invocation {
+ kind: InvocationKind::Attr {
+ attr,
+ item,
+ derives,
+ after_derive,
},
- explanation,
- );
+ ..invoc
+ });
}
};
fragment_kind.expect_from_annotatables(items)
InvocationKind::Derive { path, item } => match ext {
SyntaxExtensionKind::Derive(expander)
| SyntaxExtensionKind::LegacyDerive(expander) => {
- if !item.derive_allowed() {
- return ExpandResult::Ready(fragment_kind.dummy(span));
- }
if let SyntaxExtensionKind::Derive(..) = ext {
self.gate_proc_macro_input(&item);
}
let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
let items = match expander.expand(self.cx, span, &meta, item) {
ExpandResult::Ready(items) => items,
- ExpandResult::Retry(item, explanation) => {
+ ExpandResult::Retry(item) => {
// Reassemble the original invocation for retrying.
- return ExpandResult::Retry(
- Invocation {
- kind: InvocationKind::Derive { path: meta.path, item },
- ..invoc
- },
- explanation,
- );
+ return ExpandResult::Retry(Invocation {
+ kind: InvocationKind::Derive { path: meta.path, item },
+ ..invoc
+ });
}
};
fragment_kind.expect_from_annotatables(items)
| Annotatable::TraitItem(_)
| Annotatable::ImplItem(_)
| Annotatable::ForeignItem(_) => return,
- Annotatable::Stmt(_) => "statements",
+ Annotatable::Stmt(stmt) => {
+ // Attributes are stable on item statements,
+ // but unstable on all other kinds of statements
+ if stmt.is_item() {
+ return;
+ }
+ "statements"
+ }
Annotatable::Expr(_) => "expressions",
Annotatable::Arm(..)
| Annotatable::Field(..)
fn collect_attr(
&mut self,
- attr: Option<ast::Attribute>,
- derives: Vec<Path>,
+ (attr, derives, after_derive): (Option<ast::Attribute>, Vec<Path>, bool),
item: Annotatable,
kind: AstFragmentKind,
- after_derive: bool,
) -> AstFragment {
self.collect(
kind,
attrs: &mut Vec<ast::Attribute>,
after_derive: &mut bool,
) -> Option<ast::Attribute> {
- let attr = attrs
+ attrs
.iter()
.position(|a| {
if a.has_name(sym::derive) {
}
!self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
})
- .map(|i| attrs.remove(i));
- if let Some(attr) = &attr {
- if !self.cx.ecfg.custom_inner_attributes()
- && attr.style == ast::AttrStyle::Inner
- && !attr.has_name(sym::test)
- {
- feature_err(
- &self.cx.sess.parse_sess,
- sym::custom_inner_attributes,
- attr.span,
- "non-builtin inner attributes are unstable",
- )
- .emit();
- }
- }
- attr
+ .map(|i| attrs.remove(i))
}
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
- fn classify_item(
+ fn take_first_attr(
&mut self,
item: &mut impl HasAttrs,
- ) -> (Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool) {
+ ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
item.visit_attrs(|mut attrs| {
traits = collect_derives(&mut self.cx, &mut attrs);
});
- (attr, traits, after_derive)
+ if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None }
}
- /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
+ /// Alternative to `take_first_attr()` that ignores `#[derive]` so invocations fallthrough
/// to the unused-attributes lint (making it an error on statements and expressions
/// is a breaking change)
- fn classify_nonitem(
+ fn take_first_attr_no_derive(
&mut self,
nonitem: &mut impl HasAttrs,
- ) -> (Option<ast::Attribute>, /* after_derive */ bool) {
+ ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
let (mut attr, mut after_derive) = (None, false);
nonitem.visit_attrs(|mut attrs| {
attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
});
- (attr, after_derive)
+ attr.map(|attr| (Some(attr), Vec::new(), after_derive))
}
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
visit_clobber(expr.deref_mut(), |mut expr| {
self.cfg.configure_expr_kind(&mut expr.kind);
- // ignore derives so they remain unused
- let (attr, after_derive) = self.classify_nonitem(&mut expr);
-
- if let Some(ref attr_value) = attr {
+ if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
// Collect the invoc regardless of whether or not attributes are permitted here
// expansion will eat the attribute so it won't error later.
- self.cfg.maybe_emit_expr_attr_err(attr_value);
+ attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
// AstFragmentKind::Expr requires the macro to emit an expression.
return self
- .collect_attr(
- attr,
- vec![],
- Annotatable::Expr(P(expr)),
- AstFragmentKind::Expr,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr)
.make_expr()
.into_inner();
}
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
let mut arm = configure!(self, arm);
- let (attr, traits, after_derive) = self.classify_item(&mut arm);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut arm) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::Arm(arm),
- AstFragmentKind::Arms,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms)
.make_arms();
}
fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> {
let mut field = configure!(self, field);
- let (attr, traits, after_derive) = self.classify_item(&mut field);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut field) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::Field(field),
- AstFragmentKind::Fields,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Field(field), AstFragmentKind::Fields)
.make_fields();
}
fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> {
let mut fp = configure!(self, fp);
- let (attr, traits, after_derive) = self.classify_item(&mut fp);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut fp) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::FieldPat(fp),
- AstFragmentKind::FieldPats,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::FieldPat(fp), AstFragmentKind::FieldPats)
.make_field_patterns();
}
fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
let mut p = configure!(self, p);
- let (attr, traits, after_derive) = self.classify_item(&mut p);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut p) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::Param(p),
- AstFragmentKind::Params,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params)
.make_params();
}
fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> {
let mut sf = configure!(self, sf);
- let (attr, traits, after_derive) = self.classify_item(&mut sf);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut sf) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::StructField(sf),
- AstFragmentKind::StructFields,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::StructField(sf), AstFragmentKind::StructFields)
.make_struct_fields();
}
fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
let mut variant = configure!(self, variant);
- let (attr, traits, after_derive) = self.classify_item(&mut variant);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut variant) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::Variant(variant),
- AstFragmentKind::Variants,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants)
.make_variants();
}
expr.filter_map(|mut expr| {
self.cfg.configure_expr_kind(&mut expr.kind);
- // Ignore derives so they remain unused.
- let (attr, after_derive) = self.classify_nonitem(&mut expr);
-
- if let Some(ref attr_value) = attr {
- self.cfg.maybe_emit_expr_attr_err(attr_value);
+ if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
+ attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
return self
- .collect_attr(
- attr,
- vec![],
- Annotatable::Expr(P(expr)),
- AstFragmentKind::OptExpr,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
.make_opt_expr()
.map(|expr| expr.into_inner());
}
// we'll expand attributes on expressions separately
if !stmt.is_expr() {
- let (attr, derives, after_derive) = if stmt.is_item() {
- // FIXME: Handle custom attributes on statements (#15701)
- (None, vec![], false)
+ let attr = if stmt.is_item() {
+ self.take_first_attr(&mut stmt)
} else {
- // ignore derives on non-item statements so it falls through
- // to the unused-attributes lint
- let (attr, after_derive) = self.classify_nonitem(&mut stmt);
- (attr, vec![], after_derive)
+ // Ignore derives on non-item statements for backwards compatibility.
+ // This will result in a unused attribute warning
+ self.take_first_attr_no_derive(&mut stmt)
};
- if attr.is_some() || !derives.is_empty() {
+ if let Some(attr) = attr {
return self
- .collect_attr(
- attr,
- derives,
- Annotatable::Stmt(P(stmt)),
- AstFragmentKind::Stmts,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
.make_stmts();
}
}
if let StmtKind::MacCall(mac) = stmt.kind {
- let MacCallStmt { mac, style, attrs } = mac.into_inner();
+ let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner();
self.check_attributes(&attrs);
let mut placeholder =
self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts();
}
// The placeholder expander gives ids to statements, so we avoid folding the id here.
- let ast::Stmt { id, kind, span, tokens } = stmt;
+ let ast::Stmt { id, kind, span } = stmt;
noop_flat_map_stmt_kind(kind, self)
.into_iter()
- .map(|kind| ast::Stmt { id, kind, span, tokens: tokens.clone() })
+ .map(|kind| ast::Stmt { id, kind, span })
.collect()
}
fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let mut item = configure!(self, item);
- let (attr, traits, after_derive) = self.classify_item(&mut item);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut item) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::Item(item),
- AstFragmentKind::Items,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items)
.make_items();
}
fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let mut item = configure!(self, item);
- let (attr, traits, after_derive) = self.classify_item(&mut item);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut item) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::TraitItem(item),
- AstFragmentKind::TraitItems,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems)
.make_trait_items();
}
fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let mut item = configure!(self, item);
- let (attr, traits, after_derive) = self.classify_item(&mut item);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut item) {
return self
- .collect_attr(
- attr,
- traits,
- Annotatable::ImplItem(item),
- AstFragmentKind::ImplItems,
- after_derive,
- )
+ .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems)
.make_impl_items();
}
&mut self,
mut foreign_item: P<ast::ForeignItem>,
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
- let (attr, traits, after_derive) = self.classify_item(&mut foreign_item);
-
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut foreign_item) {
return self
.collect_attr(
attr,
- traits,
Annotatable::ForeignItem(foreign_item),
AstFragmentKind::ForeignItems,
- after_derive,
)
.make_foreign_items();
}
) -> SmallVec<[ast::GenericParam; 1]> {
let mut param = configure!(self, param);
- let (attr, traits, after_derive) = self.classify_item(&mut param);
- if attr.is_some() || !traits.is_empty() {
+ if let Some(attr) = self.take_first_attr(&mut param) {
return self
.collect_attr(
attr,
- traits,
Annotatable::GenericParam(param),
AstFragmentKind::GenericParams,
- after_derive,
)
.make_generic_params();
}
fn proc_macro_hygiene(&self) -> bool {
self.features.map_or(false, |features| features.proc_macro_hygiene)
}
- fn custom_inner_attributes(&self) -> bool {
- self.features.map_or(false, |features| features.custom_inner_attributes)
- }
}
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
_ => panic!(
- "unexpected mbe::TokenTree::{{Sequence or Delimited}} \
+ "{}",
+ "unexpected mbe::TokenTree::{Sequence or Delimited} \
in follow set checker"
),
}
mac: mac_placeholder(),
style: ast::MacStmtStyle::Braces,
attrs: ast::AttrVec::new(),
+ tokens: None,
});
- ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac), tokens: None }
+ ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) }
}]),
AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
attrs: Default::default(),
// FIXME: We will need to preserve the original semicolon token and
// span as part of #15701
- let empty_stmt = ast::Stmt {
- id: ast::DUMMY_NODE_ID,
- kind: ast::StmtKind::Empty,
- span: DUMMY_SP,
- tokens: None,
- };
+ let empty_stmt =
+ ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Empty, span: DUMMY_SP };
if let Some(stmt) = stmts.pop() {
if stmt.has_trailing_semicolon() {
use crate::base::{self, *};
use crate::proc_macro_server;
+use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::{self as ast, *};
_meta_item: &ast::MetaItem,
item: Annotatable,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
+ // We need special handling for statement items
+ // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
+ let mut is_stmt = false;
let item = match item {
- Annotatable::Arm(..)
- | Annotatable::Field(..)
- | Annotatable::FieldPat(..)
- | Annotatable::GenericParam(..)
- | Annotatable::Param(..)
- | Annotatable::StructField(..)
- | Annotatable::Variant(..) => panic!("unexpected annotatable"),
- Annotatable::Item(item) => item,
- Annotatable::ImplItem(_)
- | Annotatable::TraitItem(_)
- | Annotatable::ForeignItem(_)
- | Annotatable::Stmt(_)
- | Annotatable::Expr(_) => {
- ecx.span_err(
- span,
- "proc-macro derives may only be applied to a struct, enum, or union",
- );
- return ExpandResult::Ready(Vec::new());
+ Annotatable::Item(item) => token::NtItem(item),
+ Annotatable::Stmt(stmt) => {
+ is_stmt = true;
+ assert!(stmt.is_item());
+
+ // A proc macro can't observe the fact that we're passing
+ // them an `NtStmt` - it can only see the underlying tokens
+ // of the wrapped item
+ token::NtStmt(stmt.into_inner())
}
+ _ => unreachable!(),
};
- match item.kind {
- ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..) => {}
- _ => {
- ecx.span_err(
- span,
- "proc-macro derives may only be applied to a struct, enum, or union",
- );
- return ExpandResult::Ready(Vec::new());
- }
- }
-
- let item = token::NtItem(item);
let input = if item.pretty_printing_compatibility_hack() {
TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
} else {
loop {
match parser.parse_item() {
Ok(None) => break,
- Ok(Some(item)) => items.push(Annotatable::Item(item)),
+ Ok(Some(item)) => {
+ if is_stmt {
+ items.push(Annotatable::Stmt(P(ecx.stmt_item(span, item))));
+ } else {
+ items.push(Annotatable::Item(item));
+ }
+ }
Err(mut err) => {
err.emit();
break;
/// Allows using the `#[linkage = ".."]` attribute.
(active, linkage, "1.0.0", Some(29603), None),
- /// Allows features specific to OIBIT (auto traits).
- (active, optin_builtin_traits, "1.0.0", Some(13231), None),
-
/// Allows using `box` in patterns (RFC 469).
(active, box_patterns, "1.0.0", Some(29641), None),
/// purpose as `#[allow_internal_unstable]`.
(active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
+ /// Allows features specific to auto traits.
+ /// Renamed from `optin_builtin_traits`.
+ (active, auto_traits, "1.50.0", Some(13231), None),
+
// no-tracking-issue-end
// -------------------------------------------------------------------------
/// Allows using custom attributes (RFC 572).
(removed, custom_attribute, "1.0.0", Some(29642), None,
Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
+ /// Allows features specific to OIBIT (now called auto traits).
+ /// Renamed to `auto_traits`.
+ (removed, optin_builtin_traits, "1.0.0", Some(13231), None,
+ Some("renamed to `auto_traits`")),
(removed, pushpop_unsafe, "1.2.0", None, None, None),
(removed, needs_allocator, "1.4.0", Some(27389), None,
Some("subsumed by `#![feature(allocator_internals)]`")),
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
/// Allows `#[no_debug]`.
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
-
/// Allows comparing raw pointers during const eval.
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
Some("cannot be allowed in const eval in any meaningful way")),
[] field_pat: rustc_hir::FieldPat<$tcx>,
[] fn_decl: rustc_hir::FnDecl<$tcx>,
[] foreign_item: rustc_hir::ForeignItem<$tcx>,
+ [few] foreign_item_ref: rustc_hir::ForeignItemRef<$tcx>,
[] impl_item_ref: rustc_hir::ImplItemRef<$tcx>,
[few] inline_asm: rustc_hir::InlineAsm<$tcx>,
[few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
Tool,
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
DeriveHelper,
+ /// Single-segment custom attribute registered by a derive macro
+ /// but used before that derive macro was expanded (deprecated).
+ DeriveHelperCompat,
/// Single-segment custom attribute registered with `#[register_attr]`.
Registered,
}
match self {
NonMacroAttrKind::Builtin => "built-in attribute",
NonMacroAttrKind::Tool => "tool attribute",
- NonMacroAttrKind::DeriveHelper => "derive helper attribute",
+ NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => {
+ "derive helper attribute"
+ }
NonMacroAttrKind::Registered => "explicitly registered attribute",
}
}
/// Users of some attributes cannot mark them as used, so they are considered always used.
pub fn is_used(self) -> bool {
match self {
- NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper => true,
+ NonMacroAttrKind::Tool
+ | NonMacroAttrKind::DeriveHelper
+ | NonMacroAttrKind::DeriveHelperCompat => true,
NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false,
}
}
pub items: BTreeSet<HirId>,
pub trait_items: BTreeSet<TraitItemId>,
pub impl_items: BTreeSet<ImplItemId>,
+ pub foreign_items: BTreeSet<ForeignItemId>,
}
/// A type representing only the top-level module.
pub trait_items: BTreeMap<TraitItemId, TraitItem<'hir>>,
pub impl_items: BTreeMap<ImplItemId, ImplItem<'hir>>,
+ pub foreign_items: BTreeMap<ForeignItemId, ForeignItem<'hir>>,
pub bodies: BTreeMap<BodyId, Body<'hir>>,
pub trait_impls: BTreeMap<DefId, Vec<HirId>>,
&self.impl_items[&id]
}
+ pub fn foreign_item(&self, id: ForeignItemId) -> &ForeignItem<'hir> {
+ &self.foreign_items[&id]
+ }
+
pub fn body(&self, id: BodyId) -> &Body<'hir> {
&self.bodies[&id]
}
for impl_item in self.impl_items.values() {
visitor.visit_impl_item(impl_item);
}
+
+ for foreign_item in self.foreign_items.values() {
+ visitor.visit_foreign_item(foreign_item);
+ }
}
/// A parallel version of `visit_all_item_likes`.
par_for_each_in(&self.impl_items, |(_, impl_item)| {
visitor.visit_impl_item(impl_item);
});
+ },
+ {
+ par_for_each_in(&self.foreign_items, |(_, foreign_item)| {
+ visitor.visit_foreign_item(foreign_item);
+ });
}
);
}
}
// The bodies for items are stored "out of line", in a separate
-// hashmap in the `Crate`. Here we just record the node-id of the item
+// hashmap in the `Crate`. Here we just record the hir-id of the item
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
pub struct TraitItemId {
}
// The bodies for items are stored "out of line", in a separate
-// hashmap in the `Crate`. Here we just record the node-id of the item
+// hashmap in the `Crate`. Here we just record the hir-id of the item
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
pub struct ImplItemId {
pub item_ids: &'hir [ItemId],
}
-#[derive(Debug, HashStable_Generic)]
-pub struct ForeignMod<'hir> {
- pub abi: Abi,
- pub items: &'hir [ForeignItem<'hir>],
-}
-
#[derive(Encodable, Debug, HashStable_Generic)]
pub struct GlobalAsm {
pub asm: Symbol,
}
// The bodies for items are stored "out of line", in a separate
-// hashmap in the `Crate`. Here we just record the node-id of the item
+// hashmap in the `Crate`. Here we just record the hir-id of the item
// so it can fetched later.
#[derive(Copy, Clone, Encodable, Debug)]
pub struct ItemId {
/// A module.
Mod(Mod<'hir>),
/// An external module, e.g. `extern { .. }`.
- ForeignMod(ForeignMod<'hir>),
+ ForeignMod { abi: Abi, items: &'hir [ForeignItemRef<'hir>] },
/// Module-level inline assembly (from `global_asm!`).
GlobalAsm(&'hir GlobalAsm),
/// A type alias, e.g., `type Foo = Bar<u8>`.
Type,
}
+// The bodies for items are stored "out of line", in a separate
+// hashmap in the `Crate`. Here we just record the hir-id of the item
+// so it can fetched later.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
+pub struct ForeignItemId {
+ pub hir_id: HirId,
+}
+
+/// A reference from a foreign block to one of its items. This
+/// contains the item's ID, naturally, but also the item's name and
+/// some other high-level details (like whether it is an associated
+/// type or method, and whether it is public). This allows other
+/// passes to find the impl they want without loading the ID (which
+/// means fewer edges in the incremental compilation graph).
+#[derive(Debug, HashStable_Generic)]
+pub struct ForeignItemRef<'hir> {
+ pub id: ForeignItemId,
+ #[stable_hasher(project(name))]
+ pub ident: Ident,
+ pub span: Span,
+ pub vis: Visibility<'hir>,
+}
+
#[derive(Debug, HashStable_Generic)]
pub struct ForeignItem<'hir> {
#[stable_hasher(project(name))]
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) {
self.visitor.visit_impl_item(impl_item);
}
+
+ fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) {
+ self.visitor.visit_foreign_item(foreign_item);
+ }
}
pub trait IntoVisitor<'hir> {
fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>) {
self.0.into_visitor().visit_impl_item(impl_item);
}
+
+ fn visit_foreign_item(&self, foreign_item: &'hir ForeignItem<'hir>) {
+ self.0.into_visitor().visit_foreign_item(foreign_item);
+ }
}
#[derive(Copy, Clone)]
fn item(&self, id: HirId) -> &'hir Item<'hir>;
fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>;
+ fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
}
/// An erased version of `Map<'hir>`, using dynamic dispatch.
fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
self.0.impl_item(id)
}
+ fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ self.0.foreign_item(id)
+ }
}
/// Specifies what nested things a visitor wants to visit. The most
walk_list!(self, visit_impl_item, opt_item);
}
+ /// Like `visit_nested_item()`, but for foreign items. See
+ /// `visit_nested_item()` for advice on when to override this
+ /// method.
+ fn visit_nested_foreign_item(&mut self, id: ForeignItemId) {
+ let opt_item = self.nested_visit_map().inter().map(|map| map.foreign_item(id));
+ walk_list!(self, visit_foreign_item, opt_item);
+ }
+
/// Invoked to visit the body of a function, method or closure. Like
/// visit_nested_item, does nothing by default unless you override
/// `nested_visit_map` to return other than `None`, in which case it will walk
fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) {
walk_impl_item(self, ii)
}
+ fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef<'v>) {
+ walk_foreign_item_ref(self, ii)
+ }
fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef<'v>) {
walk_impl_item_ref(self, ii)
}
// `visit_mod()` takes care of visiting the `Item`'s `HirId`.
visitor.visit_mod(module, item.span, item.hir_id)
}
- ItemKind::ForeignMod(ref foreign_module) => {
+ ItemKind::ForeignMod { abi: _, items } => {
visitor.visit_id(item.hir_id);
- walk_list!(visitor, visit_foreign_item, foreign_module.items);
+ walk_list!(visitor, visit_foreign_item_ref, items);
}
ItemKind::GlobalAsm(_) => {
visitor.visit_id(item.hir_id);
}
}
+pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
+ visitor: &mut V,
+ foreign_item_ref: &'v ForeignItemRef<'v>,
+) {
+ // N.B., deliberately force a compilation error if/when new fields are added.
+ let ForeignItemRef { id, ident, span: _, ref vis } = *foreign_item_ref;
+ visitor.visit_nested_foreign_item(id);
+ visitor.visit_ident(ident);
+ visitor.visit_vis(vis);
+}
+
pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
let ImplItemRef { id, ident, ref kind, span: _, ref vis, ref defaultness } = *impl_item_ref;
-use super::{ImplItem, Item, TraitItem};
+use super::{ForeignItem, ImplItem, Item, TraitItem};
/// The "item-like visitor" defines only the top-level methods
/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
fn visit_item(&mut self, item: &'hir Item<'hir>);
fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>);
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>);
+ fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>);
}
/// A parallel variant of `ItemLikeVisitor`.
fn visit_item(&self, item: &'hir Item<'hir>);
fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>);
fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>);
+ fn visit_foreign_item(&self, foreign_item: &'hir ForeignItem<'hir>);
}
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use crate::hir::{
- BodyId, Expr, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId, Ty,
- VisibilityKind,
+ BodyId, Expr, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId,
+ Ty, VisibilityKind,
};
use crate::hir_id::{HirId, ItemLocalId};
use rustc_span::def_id::{DefPathHash, LocalDefId};
}
}
+impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId {
+ type KeyType = (DefPathHash, ItemLocalId);
+
+ #[inline]
+ fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
+ self.hir_id.to_stable_hash_key(hcx)
+ }
+}
+
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HirId {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_hir_id(*self, hasher)
}
}
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ForeignItemId {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ hcx.hash_reference_to_item(self.hir_id, hasher)
+ }
+}
+
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItemId {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_reference_to_item(self.hir_id, hasher)
ItemKind::Const(..) => Target::Const,
ItemKind::Fn(..) => Target::Fn,
ItemKind::Mod(..) => Target::Mod,
- ItemKind::ForeignMod(..) => Target::ForeignMod,
+ ItemKind::ForeignMod { .. } => Target::ForeignMod,
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
ItemKind::TyAlias(..) => Target::TyAlias,
ItemKind::OpaqueTy(..) => Target::OpaqueTy,
Item(hir::ItemId),
TraitItem(hir::TraitItemId),
ImplItem(hir::ImplItemId),
+ ForeignItem(hir::ForeignItemId),
Body(hir::BodyId),
BodyParamPat(hir::BodyId, usize),
}
Nested::Item(id) => state.print_item(self.item(id.id)),
Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+ Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)),
Nested::Body(id) => state.print_expr(&self.body(id).value),
Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat),
}
Nested::Item(id) => state.print_item(self.item(id.id)),
Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+ Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)),
Nested::Body(id) => state.print_expr(&self.body(id).value),
Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat),
}
}
}
- pub fn print_foreign_mod(&mut self, nmod: &hir::ForeignMod<'_>, attrs: &[ast::Attribute]) {
- self.print_inner_attributes(attrs);
- for item in nmod.items {
- self.print_foreign_item(item);
- }
- }
-
pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) {
if !lifetime.is_elided() {
self.print_lifetime(lifetime);
self.print_mod(_mod, &item.attrs);
self.bclose(item.span);
}
- hir::ItemKind::ForeignMod(ref nmod) => {
+ hir::ItemKind::ForeignMod { abi, items } => {
self.head("extern");
- self.word_nbsp(nmod.abi.to_string());
+ self.word_nbsp(abi.to_string());
self.bopen();
- self.print_foreign_mod(nmod, &item.attrs);
+ self.print_inner_attributes(item.attrs);
+ for item in items {
+ self.ann.nested(self, Nested::ForeignItem(item.id));
+ }
self.bclose(item.span);
}
hir::ItemKind::GlobalAsm(ref ga) => {
HirItem::Mod(..) => ("ItemMod", LABELS_HIR_ONLY),
// // An external module
- HirItem::ForeignMod(..) => ("ItemForeignMod", LABELS_HIR_ONLY),
+ HirItem::ForeignMod { .. } => ("ItemForeignMod", LABELS_HIR_ONLY),
// Module-level inline assembly (from global_asm!)
HirItem::GlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY),
fn visit_impl_item(&mut self, item: &hir::ImplItem<'_>) {
self.check_item(item.hir_id, item.span);
}
+
+ fn visit_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
+ self.check_item(item.hir_id, item.span);
+ }
}
/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
}))
}
-pub fn load_query_result_cache(sess: &Session) -> OnDiskCache<'_> {
+/// Attempts to load the query result cache from disk
+///
+/// If we are not in incremental compilation mode, returns `None`.
+/// Otherwise, tries to load the query result cache from disk,
+/// creating an empty cache if it could not be loaded.
+pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
if sess.opts.incremental.is_none() {
- return OnDiskCache::new_empty(sess.source_map());
+ return None;
}
let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
&query_cache_path(sess),
sess.is_nightly_build(),
) {
- LoadResult::Ok { data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
- _ => OnDiskCache::new_empty(sess.source_map()),
+ LoadResult::Ok { data: (bytes, start_pos) } => {
+ Some(OnDiskCache::new(sess, bytes, start_pos))
+ }
+ _ => Some(OnDiskCache::new_empty(sess.source_map())),
}
}
#![feature(allow_internal_unstable)]
-#![feature(bool_to_option)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
return;
}
}
+
+ // FIXME(const_generics): Currently, any uninferred `const` generics arguments
+ // are handled specially, but instead they should be handled in `annotate_method_call`,
+ // which currently doesn't work because this evaluates to `false` for const arguments.
+ // See https://github.com/rust-lang/rust/pull/77758 for more details.
if self.node_ty_contains_target(expr.hir_id).is_some() {
match expr.kind {
ExprKind::Closure(..) => self.found_closure = Some(&expr),
) -> DiagnosticBuilder<'tcx> {
let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None);
- let kind_str = match arg.unpack() {
- GenericArgKind::Type(_) => "type",
- GenericArgKind::Const(_) => "the value",
- GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
- };
let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
let ty_to_string = |ty: Ty<'tcx>| -> String {
.any(|span_label| span_label.label.is_some() && span_label.span == span)
&& local_visitor.found_arg_pattern.is_none()
{
+ let (kind_str, const_value) = match arg.unpack() {
+ GenericArgKind::Type(_) => ("type", None),
+ GenericArgKind::Const(_) => ("the value", Some(())),
+ GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
+ };
+
+ // FIXME(const_generics): we would like to handle const arguments
+ // as part of the normal diagnostics flow below, but there appear to
+ // be subtleties in doing so, so for now we special-case const args
+ // here.
+ if let Some(suggestion) = const_value
+ .and_then(|_| arg_data.parent_name.as_ref())
+ .map(|parent| format!("{}::<{}>", parent, arg_data.name))
+ {
+ err.span_suggestion_verbose(
+ span,
+ "consider specifying the const argument",
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+
// Avoid multiple labels pointing at `span`.
err.span_label(
span,
}
pub(super) fn asyncness(&self, local_def_id: LocalDefId) -> Option<hir::IsAsync> {
- // similar to the asyncness fn in rustc_ty::ty
+ // similar to the asyncness fn in rustc_ty_utils::ty
let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id);
let node = self.tcx().hir().get(hir_id);
let fn_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?;
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
while let Some(obligation) = self.base_iterator.next() {
if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() {
- return Some(data);
+ return Some(data.value);
}
}
None
rustc_privacy = { path = "../rustc_privacy" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_ty = { path = "../rustc_ty" }
+rustc_ty_utils = { path = "../rustc_ty_utils" }
tempfile = "3.0.5"
[target.'cfg(windows)'.dependencies]
pub fn output_file(&self) -> &Option<PathBuf> {
&self.output_file
}
+ pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
+ &self.register_lints
+ }
pub fn build_output_filenames(
&self,
sess: &Session,
rustc_passes::provide(providers);
rustc_resolve::provide(providers);
rustc_traits::provide(providers);
- rustc_ty::provide(providers);
+ rustc_ty_utils::provide(providers);
rustc_metadata::provide(providers);
rustc_lint::provide(providers);
rustc_symbol_mangling::provide(providers);
let local_def_id = tcx.hir().local_def_id(module);
tcx.ensure().check_mod_loops(local_def_id);
tcx.ensure().check_mod_attrs(local_def_id);
+ tcx.ensure().check_mod_naked_functions(local_def_id);
tcx.ensure().check_mod_unstable_api_usage(local_def_id);
tcx.ensure().check_mod_const_bodies(local_def_id);
});
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
pub(crate) fn provide(providers: &mut Providers) {
untracked!(no_parallel_llvm, true);
untracked!(parse_only, true);
untracked!(perf_stats, true);
- untracked!(polonius, true);
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
untracked!(print_link_args, true);
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
tracked!(dual_proc_macros, true);
- tracked!(fewer_names, true);
+ tracked!(fewer_names, Some(true));
tracked!(force_overflow_checks, Some(true));
tracked!(force_unstable_if_unmarked, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
tracked!(osx_rpath_install_name, true);
tracked!(panic_abort_tests, true);
tracked!(plt, Some(true));
+ tracked!(polonius, true);
tracked!(precise_enum_drop_elaboration, false);
tracked!(print_fuel, Some("abc".to_string()));
tracked!(profile, true);
tracked!(thinlto, Some(true));
tracked!(tune_cpu, Some(String::from("abc")));
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
+ tracked!(trap_unreachable, Some(false));
tracked!(treat_err_as_bug, Some(1));
tracked!(unleash_the_miri_inside_of_you, true);
tracked!(use_ctors_section, Some(true));
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
use rustc_ast::ptr::P;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_session::CrateDisambiguator;
use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session};
use rustc_span::edition::Edition;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::FileLoader;
use rustc_span::symbol::{sym, Symbol};
use smallvec::SmallVec;
if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().kind {
let span = spanned.span;
- let lev_candidate =
- find_best_match_for_name(CRATE_TYPES.iter().map(|(k, _)| k), n, None);
+ let lev_candidate = find_best_match_for_name(
+ &CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
+ n,
+ None,
+ );
if let Some(candidate) = lev_candidate {
lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::UNKNOWN_CRATE_TYPES,
id: resolver.next_node_id(),
kind: ast::StmtKind::Expr(expr),
span: rustc_span::DUMMY_SP,
- tokens: None,
}
}
id: self.resolver.next_node_id(),
span: rustc_span::DUMMY_SP,
kind: ast::StmtKind::Expr(loop_expr),
- tokens: None,
};
if self.within_static_or_const {
rustc_index = { path = "../rustc_index" }
rustc_session = { path = "../rustc_session" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_parse_format = { path = "../rustc_parse_format" }
enum InitKind {
Zeroed,
Uninit,
- };
+ }
/// Information about why a type cannot be initialized this way.
/// Contains an error message and optionally a span to point at.
use crate::levels::LintLevelsBuilder;
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use rustc_ast as ast;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability};
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
use rustc_session::SessionLintStore;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
use rustc_target::abi::LayoutOf;
self.by_name.keys().map(|name| Symbol::intern(&name)).collect::<Vec<_>>();
let suggestion = find_best_match_for_name(
- symbols.iter(),
+ &symbols,
Symbol::intern(&lint_name.to_lowercase()),
None,
);
mod methods;
mod non_ascii_idents;
mod nonstandard_style;
+mod panic_fmt;
mod passes;
mod redundant_semicolon;
mod traits;
use methods::*;
use non_ascii_idents::*;
use nonstandard_style::*;
+use panic_fmt::PanicFmt;
use redundant_semicolon::*;
use traits::*;
use types::*;
ClashingExternDeclarations: ClashingExternDeclarations::new(),
DropTraitConstraints: DropTraitConstraints,
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
+ PanicFmt: PanicFmt,
]
);
};
if !is_camel_case(name) {
cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| {
let msg = format!("{} `{}` should have an upper camel case name", sort, name);
- lint.build(&msg)
- .span_suggestion(
+ let mut err = lint.build(&msg);
+ let cc = to_camel_case(name);
+ // We cannot provide meaningful suggestions
+ // if the characters are in the category of "Lowercase Letter".
+ if name.to_string() != cc {
+ err.span_suggestion(
ident.span,
"convert the identifier to upper camel case",
to_camel_case(name),
Applicability::MaybeIncorrect,
- )
- .emit()
+ );
+ }
+
+ err.emit();
})
}
}
let sc = NonSnakeCase::to_snake_case(name);
let msg = format!("{} `{}` should have a snake case name", sort, name);
let mut err = lint.build(&msg);
- // We have a valid span in almost all cases, but we don't have one when linting a crate
- // name provided via the command line.
- if !ident.span.is_dummy() {
- err.span_suggestion(
- ident.span,
- "convert the identifier to snake case",
- sc,
- Applicability::MaybeIncorrect,
- );
- } else {
- err.help(&format!("convert the identifier to snake case: `{}`", sc));
+ // We cannot provide meaningful suggestions
+ // if the characters are in the category of "Uppercase Letter".
+ if name.to_string() != sc {
+ // We have a valid span in almost all cases, but we don't have one when linting a crate
+ // name provided via the command line.
+ if !ident.span.is_dummy() {
+ err.span_suggestion(
+ ident.span,
+ "convert the identifier to snake case",
+ sc,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.help(&format!("convert the identifier to snake case: `{}`", sc));
+ }
}
err.emit();
if name.chars().any(|c| c.is_lowercase()) {
cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
- lint.build(&format!("{} `{}` should have an upper case name", sort, name))
- .span_suggestion(
+ let mut err =
+ lint.build(&format!("{} `{}` should have an upper case name", sort, name));
+ // We cannot provide meaningful suggestions
+ // if the characters are in the category of "Lowercase Letter".
+ if name.to_string() != uc {
+ err.span_suggestion(
ident.span,
"convert the identifier to upper case",
uc,
Applicability::MaybeIncorrect,
- )
- .emit();
+ );
+ }
+
+ err.emit();
})
}
}
--- /dev/null
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_ast as ast;
+use rustc_errors::{pluralize, Applicability};
+use rustc_hir as hir;
+use rustc_middle::ty;
+use rustc_parse_format::{ParseMode, Parser, Piece};
+use rustc_span::{sym, InnerSpan};
+
+declare_lint! {
+ /// The `panic_fmt` lint detects `panic!("..")` with `{` or `}` in the string literal.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// panic!("{}");
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// `panic!("{}")` panics with the message `"{}"`, as a `panic!()` invocation
+ /// with a single argument does not use `format_args!()`.
+ /// A future edition of Rust will interpret this string as format string,
+ /// which would break this.
+ PANIC_FMT,
+ Warn,
+ "detect braces in single-argument panic!() invocations",
+ report_in_external_macro
+}
+
+declare_lint_pass!(PanicFmt => [PANIC_FMT]);
+
+impl<'tcx> LateLintPass<'tcx> for PanicFmt {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
+ if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
+ if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
+ || Some(def_id) == cx.tcx.lang_items().panic_fn()
+ {
+ check_panic(cx, f, arg);
+ }
+ }
+ }
+ }
+}
+
+fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::Lit(lit) = &arg.kind {
+ if let ast::LitKind::Str(sym, _) = lit.node {
+ let mut expn = f.span.ctxt().outer_expn_data();
+ if let Some(id) = expn.macro_def_id {
+ if cx.tcx.is_diagnostic_item(sym::std_panic_macro, id)
+ || cx.tcx.is_diagnostic_item(sym::core_panic_macro, id)
+ {
+ let fmt = sym.as_str();
+ if !fmt.contains(&['{', '}'][..]) {
+ return;
+ }
+
+ let fmt_span = arg.span.source_callsite();
+
+ let (snippet, style) =
+ match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
+ Ok(snippet) => {
+ // Count the number of `#`s between the `r` and `"`.
+ let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
+ (Some(snippet), style)
+ }
+ Err(_) => (None, None),
+ };
+
+ let mut fmt_parser =
+ Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
+ let n_arguments =
+ (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
+
+ // Unwrap another level of macro expansion if this panic!()
+ // was expanded from assert!() or debug_assert!().
+ for &assert in &[sym::assert_macro, sym::debug_assert_macro] {
+ let parent = expn.call_site.ctxt().outer_expn_data();
+ if parent
+ .macro_def_id
+ .map_or(false, |id| cx.tcx.is_diagnostic_item(assert, id))
+ {
+ expn = parent;
+ }
+ }
+
+ if n_arguments > 0 && fmt_parser.errors.is_empty() {
+ let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
+ [] => vec![fmt_span],
+ v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
+ };
+ cx.struct_span_lint(PANIC_FMT, arg_spans, |lint| {
+ let mut l = lint.build(match n_arguments {
+ 1 => "panic message contains an unused formatting placeholder",
+ _ => "panic message contains unused formatting placeholders",
+ });
+ l.note("this message is not used as a format string when given without arguments, but will be in a future Rust edition");
+ if expn.call_site.contains(arg.span) {
+ l.span_suggestion(
+ arg.span.shrink_to_hi(),
+ &format!("add the missing argument{}", pluralize!(n_arguments)),
+ ", ...".into(),
+ Applicability::HasPlaceholders,
+ );
+ l.span_suggestion(
+ arg.span.shrink_to_lo(),
+ "or add a \"{}\" format string to use the message literally",
+ "\"{}\", ".into(),
+ Applicability::MachineApplicable,
+ );
+ }
+ l.emit();
+ });
+ } else {
+ let brace_spans: Option<Vec<_>> = snippet
+ .filter(|s| s.starts_with('"') || s.starts_with("r#"))
+ .map(|s| {
+ s.char_indices()
+ .filter(|&(_, c)| c == '{' || c == '}')
+ .map(|(i, _)| {
+ fmt_span.from_inner(InnerSpan { start: i, end: i + 1 })
+ })
+ .collect()
+ });
+ let msg = match &brace_spans {
+ Some(v) if v.len() == 1 => "panic message contains a brace",
+ _ => "panic message contains braces",
+ };
+ cx.struct_span_lint(PANIC_FMT, brace_spans.unwrap_or(vec![expn.call_site]), |lint| {
+ let mut l = lint.build(msg);
+ l.note("this message is not used as a format string, but will be in a future Rust edition");
+ if expn.call_site.contains(arg.span) {
+ l.span_suggestion(
+ arg.span.shrink_to_lo(),
+ "add a \"{}\" format string to use the message literally",
+ "\"{}\", ".into(),
+ Applicability::MachineApplicable,
+ );
+ }
+ l.emit();
+ });
+ }
+ }
+ }
+ }
+ }
+}
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),
+ (_, seq) => {
+ maybe_lint_redundant_semis(cx, seq, after_item_stmt);
+ after_item_stmt = matches!(stmt.kind, StmtKind::Item(_));
+ }
}
}
- maybe_lint_redundant_semis(cx, &mut seq);
+ maybe_lint_redundant_semis(cx, &mut seq, after_item_stmt);
}
}
-fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
+fn maybe_lint_redundant_semis(
+ cx: &EarlyContext<'_>,
+ seq: &mut Option<(Span, bool)>,
+ after_item_stmt: bool,
+) {
if let Some((span, multiple)) = seq.take() {
// FIXME: Find a better way of ignoring the trailing
// semicolon from macro expansion
if span == rustc_span::DUMMY_SP {
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")
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
struct ProhibitOpaqueTypes<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
- };
+ }
impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
type BreakTy = Ty<'tcx>;
/// ```rust
/// #![feature(box_syntax)]
/// fn main() {
- /// let a = (box [1,2,3]).len();
+ /// let a = (box [1, 2, 3]).len();
/// }
/// ```
///
///
/// impl<T: ?Sized> MyIterator for T where T: Iterator { }
///
- /// let x = vec![1,2,3];
+ /// let x = vec![1, 2, 3];
/// let _ = x.iter().is_sorted();
/// ```
///
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Support/LEB128.h"
#include <iostream>
const char* const Filenames[],
size_t FilenamesLen,
RustStringRef BufferOut) {
- // LLVM 11's CoverageFilenamesSectionWriter uses its new `Version4` format,
- // so we're manually writing the `Version3` format ourselves.
- RawRustStringOstream OS(BufferOut);
- encodeULEB128(FilenamesLen, OS);
+ SmallVector<StringRef,32> FilenameRefs;
for (size_t i = 0; i < FilenamesLen; i++) {
- StringRef Filename(Filenames[i]);
- encodeULEB128(Filename.size(), OS);
- OS << Filename;
+ FilenameRefs.push_back(StringRef(Filenames[i]));
}
+ auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter(
+ makeArrayRef(FilenameRefs));
+ RawRustStringOstream OS(BufferOut);
+ FilenamesWriter.write(OS);
}
extern "C" void LLVMRustCoverageWriteMappingToBuffer(
return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
}
-extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) {
- StringRef NameRef(Name);
- return IndexedInstrProf::ComputeHash(NameRef);
+extern "C" uint64_t LLVMRustCoverageHashCString(const char *StrVal) {
+ StringRef StrRef(StrVal);
+ return IndexedInstrProf::ComputeHash(StrRef);
+}
+
+extern "C" uint64_t LLVMRustCoverageHashByteArray(
+ const char *Bytes,
+ unsigned NumBytes) {
+ StringRef StrRef(Bytes, NumBytes);
+ return IndexedInstrProf::ComputeHash(StrRef);
}
-extern "C" void LLVMRustCoverageWriteSectionNameToString(LLVMModuleRef M,
- RustStringRef Str) {
+static void WriteSectionNameToString(LLVMModuleRef M,
+ InstrProfSectKind SK,
+ RustStringRef Str) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
- auto name = getInstrProfSectionName(IPSK_covmap,
- TargetTriple.getObjectFormat());
+ auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat());
RawRustStringOstream OS(Str);
OS << name;
}
+extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M,
+ RustStringRef Str) {
+ WriteSectionNameToString(M, IPSK_covmap, Str);
+}
+
+extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
+ RustStringRef Str) {
+#if LLVM_VERSION_GE(11, 0)
+ WriteSectionNameToString(M, IPSK_covfun, Str);
+// else do nothing; the `Version` check will abort codegen on the Rust side
+#endif
+}
+
extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
auto name = getCoverageMappingVarName();
RawRustStringOstream OS(Str);
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
+#if LLVM_VERSION_GE(11, 0)
+ return coverage::CovMapVersion::Version4;
+#else
return coverage::CovMapVersion::Version3;
+#endif
}
const char *Name, size_t NameLen) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
GlobalObject *GV = unwrap<GlobalObject>(V);
- if (!TargetTriple.isOSBinFormatMachO()) {
+ if (TargetTriple.supportsCOMDAT()) {
StringRef NameRef(Name, NameLen);
GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef));
}
tcx: TyCtxt<'tcx>,
id: SerializedDepNodeIndex
) -> Option<Self::Value> {
- tcx.queries.on_disk_cache.try_load_query_result(tcx, id)
+ tcx.queries.on_disk_cache.as_ref().and_then(|c| c.try_load_query_result(tcx, id))
}
}
};
impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
- let fm = match it.kind {
- hir::ItemKind::ForeignMod(ref fm) => fm,
+ let items = match it.kind {
+ hir::ItemKind::ForeignMod { items, .. } => items,
_ => return,
};
let foreign_items =
- fm.items.iter().map(|it| self.tcx.hir().local_def_id(it.hir_id).to_def_id()).collect();
+ items.iter().map(|it| self.tcx.hir().local_def_id(it.id.hir_id).to_def_id()).collect();
self.modules.push(ForeignModule {
foreign_items,
def_id: self.tcx.hir().local_def_id(it.hir_id).to_def_id(),
fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
+ fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(bool_to_option)]
#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
- let fm = match it.kind {
- hir::ItemKind::ForeignMod(ref fm) => fm,
+ let abi = match it.kind {
+ hir::ItemKind::ForeignMod { abi, .. } => abi,
_ => return,
};
- if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic {
+ if abi == Abi::Rust || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
return;
}
fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
+ fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
}
impl<'tcx> Collector<'tcx> {
impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
- let fm = match it.kind {
- hir::ItemKind::ForeignMod(ref fm) => fm,
+ let abi = match it.kind {
+ hir::ItemKind::ForeignMod { abi, .. } => abi,
_ => return,
};
- if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic {
+ if abi == Abi::Rust || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
return;
}
fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
+ fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
}
impl Collector<'tcx> {
EntryKind::TraitAlias => DefKind::TraitAlias,
EntryKind::Enum(..) => DefKind::Enum,
EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang),
+ EntryKind::ProcMacro(kind) => DefKind::Macro(kind),
EntryKind::ForeignType => DefKind::ForeignTy,
EntryKind::Impl(_) => DefKind::Impl,
EntryKind::Closure => DefKind::Closure,
}
impl<'a, 'tcx> CrateMetadataRef<'a> {
- fn is_proc_macro(&self, id: DefIndex) -> bool {
- self.root
- .proc_macro_data
- .as_ref()
- .and_then(|data| data.macros.decode(self).find(|x| *x == id))
- .is_some()
- }
-
fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
}
fn kind(&self, item_id: DefIndex) -> EntryKind {
- assert!(!self.is_proc_macro(item_id));
self.maybe_kind(item_id).unwrap_or_else(|| {
bug!(
"CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
}
fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
- if !self.is_proc_macro(item_index) {
- let name = self
- .def_key(item_index)
- .disambiguated_data
- .data
- .get_opt_name()
- .expect("no name in item_ident");
- let span = self
- .root
- .tables
- .ident_span
- .get(self, item_index)
- .map(|data| data.decode((self, sess)))
- .unwrap_or_else(|| panic!("Missing ident span for {:?} ({:?})", name, item_index));
- Ident::new(name, span)
- } else {
- Ident::new(
- Symbol::intern(self.raw_proc_macro(item_index).name()),
- self.get_span(item_index, sess),
- )
- }
+ let name = self
+ .def_key(item_index)
+ .disambiguated_data
+ .data
+ .get_opt_name()
+ .expect("no name in item_ident");
+ let span = self
+ .root
+ .tables
+ .ident_span
+ .get(self, item_index)
+ .map(|data| data.decode((self, sess)))
+ .unwrap_or_else(|| panic!("Missing ident span for {:?} ({:?})", name, item_index));
+ Ident::new(name, span)
}
fn def_kind(&self, index: DefIndex) -> DefKind {
- if !self.is_proc_macro(index) {
- self.kind(index).def_kind()
- } else {
- DefKind::Macro(macro_kind(self.raw_proc_macro(index)))
- }
+ self.kind(index).def_kind()
}
fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
}
fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
- self.root.tables.ty.get(self, id).unwrap().decode((self, tcx))
+ self.root
+ .tables
+ .ty
+ .get(self, id)
+ .unwrap_or_else(|| panic!("Not a type: {:?}", id))
+ .decode((self, tcx))
}
fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
- match self.is_proc_macro(id) {
- true => self.root.proc_macro_data.as_ref().unwrap().stability,
- false => self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)),
- }
+ self.root.tables.stability.get(self, id).map(|stab| stab.decode(self))
}
fn get_const_stability(&self, id: DefIndex) -> Option<attr::ConstStability> {
}
fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
- self.root
- .tables
- .deprecation
- .get(self, id)
- .filter(|_| !self.is_proc_macro(id))
- .map(|depr| depr.decode(self))
+ self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self))
}
fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
- match self.is_proc_macro(id) {
- true => ty::Visibility::Public,
- false => self.root.tables.visibility.get(self, id).unwrap().decode(self),
- }
+ self.root.tables.visibility.get(self, id).unwrap().decode(self)
}
fn get_impl_data(&self, id: DefIndex) -> ImplData {
}
fn is_item_mir_available(&self, id: DefIndex) -> bool {
- !self.is_proc_macro(id) && self.root.tables.mir.get(self, id).is_some()
+ self.root.tables.mir.get(self, id).is_some()
}
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
.tables
.mir
.get(self, id)
- .filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id))
})
.tables
.mir_abstract_consts
.get(self, id)
- .filter(|_| !self.is_proc_macro(id))
.map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
}
.tables
.unused_generic_params
.get(self, id)
- .filter(|_| !self.is_proc_macro(id))
.map(|params| params.decode(self))
.unwrap_or_default()
}
.tables
.promoted_mir
.get(self, id)
- .filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id))
})
#[inline]
fn def_key(&self, index: DefIndex) -> DefKey {
- *self.def_key_cache.lock().entry(index).or_insert_with(|| {
- let mut key = self.root.tables.def_keys.get(self, index).unwrap().decode(self);
- if self.is_proc_macro(index) {
- let name = self.raw_proc_macro(index).name();
- key.disambiguated_data.data = DefPathData::MacroNs(Symbol::intern(name));
- }
- key
- })
+ *self
+ .def_key_cache
+ .lock()
+ .entry(index)
+ .or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self))
}
// Returns the path leading to the thing with this `id`.
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::definitions::DefPathData;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
use rustc_hir::lang_items;
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_serialize::{opaque, Encodable, Encoder};
use rustc_session::config::CrateType;
-use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext};
+use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
use rustc_target::abi::VariantIdx;
hir::ItemKind::Mod(ref m) => {
return self.encode_info_for_mod(item.hir_id, m, &item.attrs);
}
- hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod,
+ hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod,
hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
hir::ItemKind::TyAlias(..) => EntryKind::Type,
hir::ItemKind::OpaqueTy(..) => {
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
// FIXME(eddyb) there should be a nicer way to do this.
match item.kind {
- hir::ItemKind::ForeignMod(ref fm) => record!(self.tables.children[def_id] <-
- fm.items
+ hir::ItemKind::ForeignMod { items, .. } => record!(self.tables.children[def_id] <-
+ items
.iter()
.map(|foreign_item| tcx.hir().local_def_id(
- foreign_item.hir_id).local_def_index)
+ foreign_item.id.hir_id).local_def_index)
),
hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <-
self.tcx.adt_def(def_id).variants.iter().map(|v| {
// so we manually encode just the information that we need
for proc_macro in &hir.krate().proc_macros {
let id = proc_macro.owner.local_def_index;
- let span = self.lazy(hir.span(*proc_macro));
+ let mut name = hir.name(*proc_macro);
+ let span = hir.span(*proc_macro);
// Proc-macros may have attributes like `#[allow_internal_unstable]`,
// so downstream crates need access to them.
- let attrs = self.lazy(hir.attrs(*proc_macro));
- self.tables.span.set(id, span);
- self.tables.attributes.set(id, attrs);
+ let attrs = hir.attrs(*proc_macro);
+ let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) {
+ MacroKind::Bang
+ } else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) {
+ MacroKind::Attr
+ } else if let Some(attr) = tcx.sess.find_by_name(attrs, sym::proc_macro_derive) {
+ // This unwrap chain should have been checked by the proc-macro harness.
+ name = attr.meta_item_list().unwrap()[0]
+ .meta_item()
+ .unwrap()
+ .ident()
+ .unwrap()
+ .name;
+ MacroKind::Derive
+ } else {
+ bug!("Unknown proc-macro type for item {:?}", id);
+ };
+
+ let mut def_key = self.tcx.hir().def_key(proc_macro.owner);
+ def_key.disambiguated_data.data = DefPathData::MacroNs(name);
+
+ let def_id = DefId::local(id);
+ record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
+ record!(self.tables.attributes[def_id] <- attrs);
+ record!(self.tables.def_keys[def_id] <- def_key);
+ record!(self.tables.ident_span[def_id] <- span);
+ record!(self.tables.span[def_id] <- span);
+ record!(self.tables.visibility[def_id] <- ty::Visibility::Public);
+ if let Some(stability) = stability {
+ record!(self.tables.stability[def_id] <- stability);
+ }
}
Some(ProcMacroData { proc_macro_decls_static, stability, macros })
| hir::ItemKind::Const(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::Mod(..)
- | hir::ItemKind::ForeignMod(..)
+ | hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem<'v>) {
// handled in `visit_item` above
}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {}
}
/// Used to prefetch queries which will be needed later by metadata encoding.
hir::ImplItemKind::TyAlias(..) => (),
}
}
+
+ fn visit_foreign_item(&self, _foreign_item: &'v hir::ForeignItem<'v>) {
+ // This should be kept in sync with `encode_info_for_foreign_item`.
+ // Foreign items contain no MIR.
+ }
}
// NOTE(eddyb) The following comment was preserved for posterity, even
use rustc_session::config::SymbolManglingVersion;
use rustc_session::CrateDisambiguator;
use rustc_span::edition::Edition;
+use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, ExpnData, ExpnId, Span};
use rustc_target::spec::{PanicStrategy, TargetTriple};
ForeignFn(Lazy<FnData>),
Mod(Lazy<ModData>),
MacroDef(Lazy<MacroDef>),
+ ProcMacro(MacroKind),
Closure,
Generator(hir::GeneratorKind),
Trait(Lazy<TraitData>),
pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
+ // We keep a lot of `DepNode`s in memory during compilation. It's not
+ // required that their size stay the same, but we don't want to change
+ // it inadvertently. This assert just ensures we're aware of any change.
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ static_assert_size!(DepNode, 17);
+
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+ static_assert_size!(DepNode, 24);
+
pub trait DepNodeExt: Sized {
/// Construct a DepNode from the given DepKind and DefPathHash. This
/// method will assert that the given DepKind actually requires a
debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
DepNode {
kind,
- hash: def_path_hash.0,
+ hash: def_path_hash.0.into(),
}
}
/// has been removed.
fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
if self.kind.can_reconstruct_query_key() {
- let def_path_hash = DefPathHash(self.hash);
+ let def_path_hash = DefPathHash(self.hash.into());
tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
} else {
None
}
fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
- self.queries.on_disk_cache.load_diagnostics(*self, prev_dep_node_index)
+ self.queries
+ .on_disk_cache
+ .as_ref()
+ .map(|c| c.load_diagnostics(*self, prev_dep_node_index))
+ .unwrap_or_default()
}
fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>) {
- self.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics)
+ if let Some(c) = self.queries.on_disk_cache.as_ref() {
+ c.store_diagnostics(dep_node_index, diagnostics)
+ }
}
fn store_diagnostics_for_anon_node(
dep_node_index: DepNodeIndex,
diagnostics: ThinVec<Diagnostic>,
) {
- self.queries.on_disk_cache.store_diagnostics_for_anon_node(dep_node_index, diagnostics)
+ if let Some(c) = self.queries.on_disk_cache.as_ref() {
+ c.store_diagnostics_for_anon_node(dep_node_index, diagnostics)
+ }
}
fn profiler(&self) -> &SelfProfilerRef {
items: _,
trait_items: _,
impl_items: _,
+ foreign_items: _,
bodies: _,
trait_impls: _,
body_ids: _,
self.visit_impl_item(self.krate.impl_item(item_id));
}
+ fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
+ self.visit_foreign_item(self.krate.foreign_item(foreign_id));
+ }
+
fn visit_nested_body(&mut self, id: BodyId) {
self.visit_body(self.krate.body(id));
}
});
}
- fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) {
- self.insert(foreign_item.span, foreign_item.hir_id, Node::ForeignItem(foreign_item));
+ fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
+ debug_assert_eq!(
+ fi.hir_id.owner,
+ self.definitions.opt_hir_id_to_local_def_id(fi.hir_id).unwrap()
+ );
+ self.with_dep_node_owner(fi.hir_id.owner, fi, |this, hash| {
+ this.insert_with_hash(fi.span, fi.hir_id, Node::ForeignItem(fi), hash);
- self.with_parent(foreign_item.hir_id, |this| {
- intravisit::walk_foreign_item(this, foreign_item);
+ this.with_parent(fi.hir_id, |this| {
+ intravisit::walk_foreign_item(this, fi);
+ });
});
}
ItemKind::TraitAlias(..) => DefKind::TraitAlias,
ItemKind::ExternCrate(_) => DefKind::ExternCrate,
ItemKind::Use(..) => DefKind::Use,
- ItemKind::ForeignMod(..) => DefKind::ForeignMod,
+ ItemKind::ForeignMod { .. } => DefKind::ForeignMod,
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
ItemKind::Impl { .. } => DefKind::Impl,
},
}
}
+ pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ match self.find(id.hir_id).unwrap() {
+ Node::ForeignItem(item) => item,
+ _ => bug!(),
+ }
+ }
+
pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap()
}
for id in &module.impl_items {
visitor.visit_impl_item(self.expect_impl_item(id.hir_id));
}
+
+ for id in &module.foreign_items {
+ visitor.visit_foreign_item(self.expect_foreign_item(id.hir_id));
+ }
}
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
let parent = self.get_parent_item(hir_id);
if let Some(entry) = self.find_entry(parent) {
if let Entry {
- node: Node::Item(Item { kind: ItemKind::ForeignMod(ref nm), .. }), ..
+ node: Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }),
+ ..
} = entry
{
- return nm.abi;
+ return *abi;
}
}
bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent))
fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
self.impl_item(id)
}
+
+ fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ self.foreign_item(id)
+ }
}
trait Named {
ItemKind::Const(..) => "const",
ItemKind::Fn(..) => "fn",
ItemKind::Mod(..) => "mod",
- ItemKind::ForeignMod(..) => "foreign mod",
+ ItemKind::ForeignMod { .. } => "foreign mod",
ItemKind::GlobalAsm(..) => "global asm",
ItemKind::TyAlias(..) => "ty",
ItemKind::OpaqueTy(..) => "opaque type",
impl ExpressionOperandId {
/// An expression operand for a "zero counter", as described in the following references:
///
- /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter>
- /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#tag>
- /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#tag>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
///
/// This operand can be used to count two or more separate code regions with a single counter,
/// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
/// after typeck.
///
/// This should be sound because the drop flags are fully algebraic, and
- /// therefore don't affect the OIBIT or outlives properties of the
+ /// therefore don't affect the auto-trait or outlives properties of the
/// generator.
pub internal: bool,
macro_rules! basic_blocks {
(mut) => (body.basic_blocks_mut().iter_enumerated_mut());
() => (body.basic_blocks().iter_enumerated());
- };
+ }
for (bb, data) in basic_blocks!($($mutability)?) {
self.visit_basic_block_data(bb, data);
}
macro_rules! type_annotations {
(mut) => (body.user_type_annotations.iter_enumerated_mut());
() => (body.user_type_annotations.iter_enumerated());
- };
+ }
for (index, annotation) in type_annotations!($($mutability)?) {
self.visit_user_type_annotation(
macro_rules! basic_blocks {
(mut) => (body.basic_blocks_mut());
() => (body.basic_blocks());
- };
+ }
let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block];
if basic_block.statements.len() == location.statement_index {
if let Some(ref $($mutability)? terminator) = basic_block.terminator {
let mut context = context;
if !place.projection.is_empty() {
- context = if context.is_mutating_use() {
- PlaceContext::MutatingUse(MutatingUseContext::Projection)
- } else {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
- };
+ if context.is_use() {
+ // ^ Only change the context if it is a real use, not a "use" in debuginfo.
+ context = if context.is_mutating_use() {
+ PlaceContext::MutatingUse(MutatingUseContext::Projection)
+ } else {
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
+ };
+ }
}
self.visit_local(&place.local, context, location);
storage(ArenaCacheSelector<'tcx>)
cache_on_disk_if { key.is_local() }
load_cached(tcx, id) {
- let generics: Option<ty::Generics> = tcx.queries.on_disk_cache
- .try_load_query_result(tcx, id);
+ let generics: Option<ty::Generics> = tcx.queries.on_disk_cache.as_ref()
+ .and_then(|c| c.try_load_query_result(tcx, id));
generics
}
}
desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
}
+ query check_mod_naked_functions(key: LocalDefId) -> () {
+ desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) }
+ }
+
query check_mod_item_types(key: LocalDefId) -> () {
desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) }
}
cache_on_disk_if { true }
load_cached(tcx, id) {
let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
- .queries.on_disk_cache
- .try_load_query_result(tcx, id);
+ .queries.on_disk_cache.as_ref()
+ .and_then(|c| c.try_load_query_result(tcx, id));
typeck_results.map(|x| &*tcx.arena.alloc(x))
}
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_hir::Constness;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec;
/// be observable directly by the user, `Reveal::All`
/// should not be used by checks which may expose
/// type equality or type contents to the user.
- /// There are some exceptions, e.g., around OIBITS and
+ /// There are some exceptions, e.g., around auto traits and
/// transmute-checking, which expose some details, but
/// not the whole concrete type of the `impl Trait`.
All,
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
/// any).
- Param(Vec<N>),
+ Param(Vec<N>, Constness),
/// Virtual calls through an object.
Object(ImplSourceObjectData<'tcx, N>),
pub fn nested_obligations(self) -> Vec<N> {
match self {
ImplSource::UserDefined(i) => i.nested,
- ImplSource::Param(n) => n,
+ ImplSource::Param(n, _) => n,
ImplSource::Builtin(i) => i.nested,
ImplSource::AutoImpl(d) => d.nested,
ImplSource::Closure(c) => c.nested,
pub fn borrow_nested_obligations(&self) -> &[N] {
match &self {
ImplSource::UserDefined(i) => &i.nested[..],
- ImplSource::Param(n) => &n[..],
+ ImplSource::Param(n, _) => &n[..],
ImplSource::Builtin(i) => &i.nested[..],
ImplSource::AutoImpl(d) => &d.nested[..],
ImplSource::Closure(c) => &c.nested[..],
substs: i.substs,
nested: i.nested.into_iter().map(f).collect(),
}),
- ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()),
+ ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData {
nested: i.nested.into_iter().map(f).collect(),
}),
/// `false` if there are no *further* obligations.
has_nested: bool,
},
- ParamCandidate(ty::PolyTraitRef<'tcx>),
+ ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
- super::ImplSource::Param(ref n) => write!(f, "ImplSourceParamData({:?})", n),
+ super::ImplSource::Param(ref n, ct) => {
+ write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
+ }
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
use rustc_hir::definitions::{DefPathHash, Definitions};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate};
+use rustc_hir::{
+ Constness, HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate,
+};
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
krate: &'tcx hir::Crate<'tcx>,
definitions: &'tcx Definitions,
dep_graph: DepGraph,
- on_disk_query_result_cache: query::OnDiskCache<'tcx>,
+ on_disk_query_result_cache: Option<query::OnDiskCache<'tcx>>,
crate_name: &str,
output_filenames: &OutputFilenames,
) -> GlobalCtxt<'tcx> {
where
E: ty::codec::OpaqueEncoder,
{
- self.queries.on_disk_cache.serialize(self, encoder)
+ self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(()))
}
/// If `true`, we should use the MIR-based borrowck, but also
// This is the impl for `&'a InternalSubsts<'a>`.
nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
+CloneLiftImpls! { for<'tcx> { Constness, } }
+
pub mod tls {
use super::{ptr_eq, GlobalCtxt, TyCtxt};
struct PolymorphizationFolder<'tcx> {
tcx: TyCtxt<'tcx>,
- };
+ }
impl ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::DUMMY_SP;
use rustc_target::abi::call::{
- ArgAbi, ArgAttribute, ArgAttributes, Conv, FnAbi, PassMode, Reg, RegKind,
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
};
use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
is_return: bool| {
// Booleans are always an i1 that needs to be zero-extended.
if scalar.is_bool() {
- attrs.set(ArgAttribute::ZExt);
+ attrs.ext(ArgExtension::Zext);
return;
}
for arg in &mut self.args {
fixup(arg, false);
}
- if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
- attrs.set(ArgAttribute::StructRet);
- }
return;
}
}
impl<'tcx> Predicate<'tcx> {
- pub fn to_opt_poly_trait_ref(self) -> Option<PolyTraitRef<'tcx>> {
+ pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
match self.skip_binders() {
- PredicateAtom::Trait(t, _) => Some(ty::Binder::bind(t.trait_ref)),
+ PredicateAtom::Trait(t, constness) => {
+ Some(ConstnessAnd { constness, value: ty::Binder::bind(t.trait_ref) })
+ }
PredicateAtom::Projection(..)
| PredicateAtom::Subtype(..)
| PredicateAtom::RegionOutlives(..)
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
pub struct ConstnessAnd<T> {
pub constness: Constness,
pub value: T,
pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
eprintln!("query stack during panic:");
- // Be careful reyling on global state here: this code is called from
+ // Be careful relying on global state here: this code is called from
// a panic hook, which means that the global `Handler` may be in a weird
// state if it was responsible for triggering the panic.
let mut i = 0;
(tcx: $tcx:tt,
input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
pub struct Queries<$tcx> {
- /// This provides access to the incrimental comilation on-disk cache for query results.
+ /// This provides access to the incremental compilation on-disk cache for query results.
/// Do not access this directly. It is only meant to be used by
/// `DepGraph::try_mark_green()` and the query infrastructure.
- pub(crate) on_disk_cache: OnDiskCache<'tcx>,
+ /// This is `None` if we are not incremental compilation mode
+ pub(crate) on_disk_cache: Option<OnDiskCache<'tcx>>,
providers: IndexVec<CrateNum, Providers>,
fallback_extern_providers: Box<Providers>,
pub(crate) fn new(
providers: IndexVec<CrateNum, Providers>,
fallback_extern_providers: Providers,
- on_disk_cache: OnDiskCache<'tcx>,
+ on_disk_cache: Option<OnDiskCache<'tcx>>,
) -> Self {
Queries {
providers,
impl<T> Binder<Option<T>> {
pub fn transpose(self) -> Option<Binder<T>> {
- match self.0 {
- Some(v) => Some(Binder(v)),
- None => None,
- }
+ self.0.map(Binder)
}
}
ensure_monomorphic_enough(tcx, tp_ty)?;
ConstValue::from_u64(tcx.type_id_hash(tp_ty))
}
- sym::variant_count => {
- if let ty::Adt(ref adt, _) = tp_ty.kind() {
- ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
- } else {
- ConstValue::from_machine_usize(0u64, &tcx)
- }
- }
+ sym::variant_count => match tp_ty.kind() {
+ ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx),
+ ty::Projection(_)
+ | ty::Opaque(_, _)
+ | ty::Param(_)
+ | ty::Bound(_, _)
+ | ty::Placeholder(_)
+ | ty::Infer(_) => throw_inval!(TooGeneric),
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Foreign(_)
+ | ty::Str
+ | ty::Array(_, _)
+ | ty::Slice(_)
+ | ty::RawPtr(_)
+ | ty::Ref(_, _, _)
+ | ty::FnDef(_, _)
+ | ty::FnPtr(_)
+ | ty::Dynamic(_, _)
+ | ty::Closure(_, _)
+ | ty::Generator(_, _, _)
+ | ty::GeneratorWitness(_)
+ | ty::Never
+ | ty::Tuple(_)
+ | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx),
+ },
other => bug!("`{}` is not a zero arg intrinsic", other),
})
}
struct UsedParamsNeedSubstVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- };
+ }
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
type BreakTy = ();
match item.kind {
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
- | hir::ItemKind::ForeignMod(..)
+ | hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Trait(..)
| hir::ItemKind::TraitAlias(..)
self.push_if_root(def_id);
}
}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {}
}
impl RootCollector<'_, 'v> {
match self_ty.kind() {
_ if is_copy => builder.copy_shim(),
- ty::Array(ty, len) => {
- let len = len.eval_usize(tcx, param_env);
- builder.array_shim(dest, src, ty, len)
- }
+ ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
ty::Closure(_, substs) => {
builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
}
}
}
- fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
+ fn array_shim(
+ &mut self,
+ dest: Place<'tcx>,
+ src: Place<'tcx>,
+ ty: Ty<'tcx>,
+ len: &'tcx ty::Const<'tcx>,
+ ) {
let tcx = self.tcx;
let span = self.span;
))),
self.make_statement(StatementKind::Assign(box (
end,
- Rvalue::Use(Operand::Constant(self.make_usize(len))),
+ Rvalue::Use(Operand::Constant(box Constant {
+ span: self.span,
+ user_ty: None,
+ literal: len,
+ })),
))),
];
self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, LangItem};
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::{
self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut,
};
+use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::{self, TraitEngine};
+use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine};
use std::mem;
use std::ops::Deref;
}
};
- // Resolve a trait method call to its concrete implementation, which may be in a
- // `const` trait impl.
- if self.tcx.features().const_trait_impl {
+ // Attempting to call a trait method?
+ if let Some(trait_id) = tcx.trait_of_item(callee) {
+ if !self.tcx.features().const_trait_impl {
+ self.check_op(ops::FnCallNonConst(callee));
+ return;
+ }
+
+ let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ Binder::bind(TraitPredicate {
+ trait_ref: TraitRef::from_method(tcx, trait_id, substs),
+ }),
+ );
+
+ let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let mut selcx = SelectionContext::new(&infcx);
+ selcx.select(&obligation).unwrap()
+ });
+
+ // If the method is provided via a where-clause that does not use the `?const`
+ // opt-out, the call is allowed.
+ if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
+ debug!(
+ "const_trait_impl: provided {:?} via where-clause in {:?}",
+ trait_ref, param_env
+ );
+ return;
+ }
+
+ // Resolve a trait method call to its concrete implementation, which may be in a
+ // `const` trait impl.
let instance = Instance::resolve(tcx, param_env, callee, substs);
debug!("Resolving ({:?}) -> {:?}", callee, instance);
if let Ok(Some(func)) = instance {
}
}
- trace!("attepting to replace {:?} with {:?}", rval, value);
+ trace!("attempting to replace {:?} with {:?}", rval, value);
if let Err(e) = self.ecx.const_validate_operand(
value,
vec![],
return false;
}
+ if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) {
+ return false;
+ }
+
match *op {
interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => {
s.is_bits()
//!
//! Depending on the values and combinations, counters can be labeled by:
//!
-//! * `id` - counter or expression ID (ascending counter IDs, starting at 1, or descending
-//! expression IDs, starting at `u32:MAX`)
-//! * `block` - the `BasicCoverageBlock` label (for example, `bcb0`) or edge label (for
-//! example `bcb0->bcb1`), for counters or expressions assigned to count a
-//! `BasicCoverageBlock` or edge. Intermediate expressions (not directly associated with
-//! a BCB or edge) will be labeled by their expression ID, unless `operation` is also
-//! specified.
-//! * `operation` - applied to expressions only, labels include the left-hand-side counter
-//! or expression label (lhs operand), the operator (`+` or `-`), and the right-hand-side
-//! counter or expression (rhs operand). Expression operand labels are generated
-//! recursively, generating labels with nested operations, enclosed in parentheses
-//! (for example: `bcb2 + (bcb0 - bcb1)`).
+//! * `id` - counter or expression ID (ascending counter IDs, starting at 1, or descending
+//! expression IDs, starting at `u32:MAX`)
+//! * `block` - the `BasicCoverageBlock` label (for example, `bcb0`) or edge label (for
+//! example `bcb0->bcb1`), for counters or expressions assigned to count a
+//! `BasicCoverageBlock` or edge. Intermediate expressions (not directly associated with
+//! a BCB or edge) will be labeled by their expression ID, unless `operation` is also
+//! specified.
+//! * `operation` - applied to expressions only, labels include the left-hand-side counter
+//! or expression label (lhs operand), the operator (`+` or `-`), and the right-hand-side
+//! counter or expression (rhs operand). Expression operand labels are generated
+//! recursively, generating labels with nested operations, enclosed in parentheses
+//! (for example: `bcb2 + (bcb0 - bcb1)`).
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use super::spans::CoverageSpan;
let should_cleanup = !opts_to_apply.is_empty();
for opt_to_apply in opts_to_apply {
+ if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) {
+ break;
+ }
+
trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);
let statements_before =
self.tcx.sess.opts.debugging_opts.inline_mir_threshold
};
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+ debug!("#[naked] present - not inlining");
+ return false;
+ }
+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
debug!("#[cold] present - not inlining");
return false;
tcx: TyCtxt<'tcx>,
}
+impl<'tcx> InstCombineVisitor<'tcx> {
+ fn should_combine(&self, rvalue: &Rvalue<'tcx>, location: Location) -> bool {
+ self.tcx.consider_optimizing(|| {
+ format!("InstCombine - Rvalue: {:?} Location: {:?}", rvalue, location)
+ })
+ }
+}
+
impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
- if self.optimizations.and_stars.remove(&location) {
+ if self.optimizations.and_stars.remove(&location) && self.should_combine(rvalue, location) {
debug!("replacing `&*`: {:?}", rvalue);
let new_place = match rvalue {
Rvalue::Ref(_, _, place) => {
}
if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {
- debug!("replacing `Len([_; N])`: {:?}", rvalue);
- *rvalue = Rvalue::Use(Operand::Constant(box constant));
+ if self.should_combine(rvalue, location) {
+ debug!("replacing `Len([_; N])`: {:?}", rvalue);
+ *rvalue = Rvalue::Use(Operand::Constant(box constant));
+ }
}
if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) {
- debug!("replacing {:?} with {:?}", rvalue, operand);
- *rvalue = Rvalue::Use(operand);
+ if self.should_combine(rvalue, location) {
+ debug!("replacing {:?} with {:?}", rvalue, operand);
+ *rvalue = Rvalue::Use(operand);
+ }
}
if let Some(place) = self.optimizations.unneeded_deref.remove(&location) {
- debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place);
- *rvalue = Rvalue::Use(Operand::Copy(place));
+ if self.should_combine(rvalue, location) {
+ debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place);
+ *rvalue = Rvalue::Use(Operand::Copy(place));
+ }
}
self.super_rvalue(rvalue, location)
impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- for block in body.basic_blocks_mut() {
+ let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+ for block in basic_blocks {
let terminator = block.terminator.as_mut().unwrap();
- if let TerminatorKind::Call {
- func: Operand::Constant(box Constant { literal: ty::Const { ty: func_ty, .. }, .. }),
- args,
- destination,
- ..
- } = &mut terminator.kind
- {
+ if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind {
+ let func_ty = func.ty(local_decls, tcx);
let (intrinsic_name, substs) = match resolve_rust_intrinsic(tcx, func_ty) {
None => continue,
Some(it) => it,
}
let param_env = tcx.param_env(body.source.def_id());
+ let def_id = body.source.def_id();
let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
'outer: for bb_idx in bbs.indices() {
+ if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) {
+ continue;
+ }
+
let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
TerminatorKind::SwitchInt {
discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
// find basic blocks with no statement and a return terminator
let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
+ let def_id = body.source.def_id();
let bbs = body.basic_blocks_mut();
for idx in bbs.indices() {
if bbs[idx].statements.is_empty()
}
for bb in bbs {
+ if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {:?} ", def_id)) {
+ break;
+ }
+
if let TerminatorKind::Goto { target } = bb.terminator().kind {
if bbs_simple_returns.contains(target) {
bb.terminator_mut().kind = TerminatorKind::Return;
return;
}
+ let def_id = body.source.def_id();
let returned_local = match local_eligible_for_nrvo(body) {
Some(l) => l,
None => {
- debug!("`{:?}` was ineligible for NRVO", body.source.def_id());
+ debug!("`{:?}` was ineligible for NRVO", def_id);
return;
}
};
+ if !tcx.consider_optimizing(|| format!("RenameReturnPlace {:?}", def_id)) {
+ return;
+ }
+
debug!(
"`{:?}` was eligible for NRVO, making {:?} the return place",
- body.source.def_id(),
- returned_local
+ def_id, returned_local
);
RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body);
opt_finder.visit_body(body);
let should_simplify = !opt_finder.optimizations.is_empty();
for (loc, target) in opt_finder.optimizations {
+ if !tcx
+ .consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", body.source.def_id()))
+ {
+ break;
+ }
+
let terminator = body.basic_blocks_mut()[loc.block].terminator_mut();
debug!("SUCCESS: replacing `drop` with goto({:?})", target);
terminator.kind = TerminatorKind::Goto { target };
let replaced = !replacements.is_empty();
for (bb, terminator_kind) in replacements {
+ if !tcx.consider_optimizing(|| {
+ format!("UnreachablePropagation {:?} ", body.source.def_id())
+ }) {
+ break;
+ }
+
body.basic_blocks_mut()[bb].terminator_mut().kind = terminator_kind;
}
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef,
- Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo,
+ Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind,
};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
impl<'tcx> MirPass<'tcx> for Validator {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
- // We need to param_env_reveal_all_normalized, as some optimizations
- // change types in ways that require unfolding opaque types.
- let param_env = tcx.param_env_reveal_all_normalized(def_id);
+ let param_env = tcx.param_env(def_id);
let mir_phase = self.mir_phase;
let always_live_locals = AlwaysLiveLocals::new(body);
}
// Normalize lifetimes away on both sides, then compare.
+ let param_env = param_env.with_reveal_all_normalized(tcx);
let normalize = |ty: Ty<'tcx>| {
tcx.normalize_erasing_regions(
param_env,
return true;
}
// Normalize projections and things like that.
- let src = self.tcx.normalize_erasing_regions(self.param_env, src);
- let dest = self.tcx.normalize_erasing_regions(self.param_env, dest);
+ // FIXME: We need to reveal_all, as some optimizations change types in ways
+ // that require unfolding opaque types.
+ let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
+ let src = self.tcx.normalize_erasing_regions(param_env, src);
+ let dest = self.tcx.normalize_erasing_regions(param_env, dest);
// Type-changing assignments can happen when subtyping is used. While
// all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type
// differences. So we compare ignoring lifetimes.
- equal_up_to_regions(self.tcx, self.param_env, src, dest)
+ equal_up_to_regions(self.tcx, param_env, src, dest)
}
}
}
}
- fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) {
- // Debuginfo can contain field projections, which count as a use of the base local. Skip
- // debuginfo so that we avoid the storage liveness assertion in that case.
- self.visit_source_info(&var_debug_info.source_info);
- }
-
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
// This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
if self.tcx.sess.opts.debugging_opts.validate_mir {
}
TerminatorKind::Call { func, args, destination, cleanup, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx);
- let func_ty = self.tcx.normalize_erasing_regions(self.param_env, func_ty);
match func_ty.kind() {
ty::FnPtr(..) | ty::FnDef(..) => {}
_ => self.fail(
expr_span,
source_info,
),
- ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))),
+ ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
+ let capture = this
+ .hir
+ .typeck_results
+ .closure_captures
+ .get(&closure_def_id)
+ .and_then(|captures| captures.get_full(&var_hir_id));
+
+ if capture.is_none() {
+ if !this.hir.tcx().features().capture_disjoint_fields {
+ bug!(
+ "No associated capture found for {:?} even though \
+ capture_disjoint_fields isn't enabled",
+ expr.kind
+ )
+ }
+ // FIXME(project-rfc-2229#24): Handle this case properly
+ }
+
+ // Unwrap until the FIXME has been resolved
+ let (capture_index, _, upvar_id) = capture.unwrap();
+ this.lower_closure_capture(block, capture_index, *upvar_id)
+ }
+
ExprKind::VarRef { id } => {
let place_builder = if this.is_bound_var_in_guard(id) {
let index = this.var_local_id(id, RefWithinGuard);
}
}
+ /// Lower a closure/generator capture by representing it as a field
+ /// access within the desugared closure/generator.
+ ///
+ /// `capture_index` is the index of the capture within the desugared
+ /// closure/generator.
+ fn lower_closure_capture(
+ &mut self,
+ block: BasicBlock,
+ capture_index: usize,
+ upvar_id: ty::UpvarId,
+ ) -> BlockAnd<PlaceBuilder<'tcx>> {
+ let closure_ty = self
+ .hir
+ .typeck_results()
+ .node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
+
+ // Captures are represented using fields inside a structure.
+ // This represents accessing self in the closure structure
+ let mut place_builder = PlaceBuilder::from(Local::new(1));
+
+ // In case of Fn/FnMut closures we must deref to access the fields
+ // Generators are considered FnOnce, so we ignore this step for them.
+ if let ty::Closure(_, closure_substs) = closure_ty.kind() {
+ match self.hir.infcx().closure_kind(closure_substs).unwrap() {
+ ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
+ place_builder = place_builder.deref();
+ }
+ ty::ClosureKind::FnOnce => {}
+ }
+ }
+
+ let substs = match closure_ty.kind() {
+ ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
+ ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
+ _ => bug!("Lowering capture for non-closure type {:?}", closure_ty)
+ };
+
+ // Access the capture by accessing the field within the Closure struct.
+ //
+ // We must have inferred the capture types since we are building MIR, therefore
+ // it's safe to call `upvar_tys` and we can unwrap here because
+ // we know that the capture exists and is the `capture_index`-th capture.
+ let var_ty = substs.upvar_tys().nth(capture_index).unwrap();
+ place_builder = place_builder.field(Field::new(capture_index), var_ty);
+
+ // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
+ // we need to deref it
+ match self.hir.typeck_results.upvar_capture(upvar_id) {
+ ty::UpvarCapture::ByRef(_) => {
+ block.and(place_builder.deref())
+ }
+ ty::UpvarCapture::ByValue(_) => block.and(place_builder),
+ }
+ }
+
/// Lower an index expression
///
/// This has two complications;
ExprKind::Box { value } => {
let value = this.hir.mirror(value);
// The `Box<T>` temporary created here is not a part of the HIR,
- // and therefore is not considered during generator OIBIT
+ // and therefore is not considered during generator auto-trait
// determination. See the comment about `box` at `yield_in_scope`.
let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span).internal());
this.cfg.push(
| ExprKind::Deref { .. }
| ExprKind::Index { .. }
| ExprKind::VarRef { .. }
- | ExprKind::SelfRef
+ | ExprKind::UpvarRef { .. }
| ExprKind::Break { .. }
| ExprKind::Continue { .. }
| ExprKind::Return { .. }
ExprKind::Field { .. }
| ExprKind::Deref { .. }
| ExprKind::Index { .. }
- | ExprKind::SelfRef
+ | ExprKind::UpvarRef { .. }
| ExprKind::VarRef { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
// Avoid creating a temporary
ExprKind::VarRef { .. }
- | ExprKind::SelfRef
+ | ExprKind::UpvarRef { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => {
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
ExprKind::Deref { arg: Expr { ty, temp_lifetime, span: expr.span, kind }.to_ref() }
}
- Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id),
+ Res::Local(var_hir_id) => convert_var(cx, var_hir_id),
_ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
}
}
-fn convert_var<'tcx>(
- cx: &mut Cx<'_, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- var_hir_id: hir::HirId,
-) -> ExprKind<'tcx> {
- let upvar_index = cx
- .typeck_results()
- .closure_captures
- .get(&cx.body_owner)
- .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
-
- debug!(
- "convert_var({:?}): upvar_index={:?}, body_owner={:?}",
- var_hir_id, upvar_index, cx.body_owner
- );
-
- let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-
- match upvar_index {
- None => ExprKind::VarRef { id: var_hir_id },
+fn convert_var<'tcx>(cx: &mut Cx<'_, 'tcx>, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
+ // We want upvars here not captures.
+ // Captures will be handled in MIR.
+ let is_upvar = cx
+ .tcx
+ .upvars_mentioned(cx.body_owner)
+ .map_or(false, |upvars| upvars.contains_key(&var_hir_id));
- Some(upvar_index) => {
- let closure_def_id = cx.body_owner;
- let upvar_id = ty::UpvarId {
- var_path: ty::UpvarPath { hir_id: var_hir_id },
- closure_expr_id: closure_def_id.expect_local(),
- };
- let var_ty = cx.typeck_results().node_type(var_hir_id);
+ debug!("convert_var({:?}): is_upvar={}, body_owner={:?}", var_hir_id, is_upvar, cx.body_owner);
- // FIXME free regions in closures are not right
- let closure_ty = cx
- .typeck_results()
- .node_type(cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
-
- // FIXME we're just hard-coding the idea that the
- // signature will be &self or &mut self and hence will
- // have a bound region with number 0
- let region = ty::ReFree(ty::FreeRegion {
- scope: closure_def_id,
- bound_region: ty::BoundRegion::BrAnon(0),
- });
- let region = cx.tcx.mk_region(region);
-
- let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
- match cx.infcx.closure_kind(closure_substs).unwrap() {
- ty::ClosureKind::Fn => {
- let ref_closure_ty = cx.tcx.mk_ref(
- region,
- ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Not },
- );
- Expr {
- ty: closure_ty,
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::Deref {
- arg: Expr {
- ty: ref_closure_ty,
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::SelfRef,
- }
- .to_ref(),
- },
- }
- }
- ty::ClosureKind::FnMut => {
- let ref_closure_ty = cx.tcx.mk_ref(
- region,
- ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Mut },
- );
- Expr {
- ty: closure_ty,
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::Deref {
- arg: Expr {
- ty: ref_closure_ty,
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::SelfRef,
- }
- .to_ref(),
- },
- }
- }
- ty::ClosureKind::FnOnce => Expr {
- ty: closure_ty,
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::SelfRef,
- },
- }
- } else {
- Expr { ty: closure_ty, temp_lifetime, span: expr.span, kind: ExprKind::SelfRef }
- };
-
- // at this point we have `self.n`, which loads up the upvar
- let field_kind =
- ExprKind::Field { lhs: self_expr.to_ref(), name: Field::new(upvar_index) };
-
- // ...but the upvar might be an `&T` or `&mut T` capture, at which
- // point we need an implicit deref
- match cx.typeck_results().upvar_capture(upvar_id) {
- ty::UpvarCapture::ByValue(_) => field_kind,
- ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref {
- arg: Expr {
- temp_lifetime,
- ty: cx.tcx.mk_ref(
- borrow.region,
- ty::TypeAndMut { ty: var_ty, mutbl: borrow.kind.to_mutbl_lossy() },
- ),
- span: expr.span,
- kind: field_kind,
- }
- .to_ref(),
- },
- }
- }
+ if is_upvar {
+ ExprKind::UpvarRef { closure_def_id: cx.body_owner, var_hir_id }
+ } else {
+ ExprKind::VarRef { id: var_hir_id }
}
}
temp_lifetime,
ty: var_ty,
span: closure_expr.span,
- kind: convert_var(cx, closure_expr, var_hir_id),
+ kind: convert_var(cx, var_hir_id),
};
match upvar_capture {
ty::UpvarCapture::ByValue(_) => captured_var.to_ref(),
ty.needs_drop(self.tcx, self.param_env)
}
+ crate fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
+ self.infcx
+ }
+
crate fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
VarRef {
id: hir::HirId,
},
- /// first argument, used for self in a closure
- SelfRef,
+ /// Used to represent upvars mentioned in a closure/generator
+ UpvarRef {
+ /// DefId of the closure/generator
+ closure_def_id: DefId,
+
+ /// HirId of the root variable
+ var_hir_id: hir::HirId,
+ },
Borrow {
borrow_kind: BorrowKind,
arg: ExprRef<'tcx>,
+++ /dev/null
-//! Note: tests specific to this file can be found in:
-//! - ui/pattern/usefulness
-//! - ui/or-patterns
-//! - ui/consts/const_in_pattern
-//! - ui/rfc-2008-non-exhaustive
-//! - probably many others
-//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
-//! reason not to, for example if they depend on a particular feature like or_patterns.
-//!
-//! 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)
-//!
-//! The algorithm implemented here is a modified version of the one described in:
-//! <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).
-//!
-//! # 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).
-//!
-//! 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).
-//!
-//! # Core concept
-//!
-//! 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.
-//!
-//! 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.
-//!
-//! 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.
-//!
-//! 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.
-//!
-//! 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.
-//!
-//!
-//! # Algorithm
-//!
-//! 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`.
-//!
-//! For example, say we have the following:
-//!
-//! ```
-//! // x: (Option<bool>, Result<()>)
-//! match x {
-//! (Some(true), _) => {}
-//! (None, Err(())) => {}
-//! (None, Err(_)) => {}
-//! }
-//! ```
-//!
-//! Here, the matrix `P` starts as:
-//!
-//! ```
-//! [
-//! [(Some(true), _)],
-//! [(None, Err(()))],
-//! [(None, Err(_))],
-//! ]
-//! ```
-//!
-//! 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.
-//!
-//! 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.
-//!
-//! There are two important operations on pattern-stacks necessary to understand the algorithm:
-//!
-//! 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.
-//!
-//! 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.
-//!
-//! 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:
-//! 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
-//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
-//! return nothing.
-//! 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
-//! 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))
-//!
-//! 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.
-//!
-//! 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))
-//!
-//! 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.
-//!
-//! 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.
-//!
-//!
-//! 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.
-//!
-//! 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))`
-//!
-//! For example, if `P` is:
-//!
-//! ```
-//! [
-//! [Some(true), _],
-//! [None, 0],
-//! ]
-//! ```
-//!
-//! 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])`.
-//!
-//! - 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))`
-//!
-//! For example, if `P` is:
-//!
-//! ```
-//! [
-//! [_, true, _],
-//! [None, false, 1],
-//! ]
-//! ```
-//!
-//! 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])`.
-//!
-//! + 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 example, if `P` is:
-//!
-//! ```
-//! [
-//! [Some(true), _],
-//! [None, 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.
-//!
-//! - 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))`
-//!
-//! 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.
-//!
-//! 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).
-use self::Constructor::*;
-use self::SliceKind::*;
-use self::Usefulness::*;
-use self::WitnessPreference::*;
-
-use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::OnceCell;
-use rustc_index::vec::Idx;
-
-use super::{compare_const_vals, PatternFoldable, PatternFolder};
-use super::{FieldPat, Pat, PatKind, PatRange};
-
-use rustc_arena::TypedArena;
-use rustc_attr::{SignedInt, UnsignedInt};
-use rustc_hir::def_id::DefId;
-use rustc_hir::{HirId, RangeEnd};
-use rustc_middle::mir::interpret::ConstValue;
-use rustc_middle::mir::Field;
-use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt};
-use rustc_session::lint;
-use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{Integer, Size, VariantIdx};
-
-use smallvec::{smallvec, SmallVec};
-use std::cmp::{self, max, min, Ordering};
-use std::fmt;
-use std::iter::{FromIterator, IntoIterator};
-use std::ops::RangeInclusive;
-
-crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
- LiteralExpander.fold_pattern(&pat)
-}
-
-struct LiteralExpander;
-
-impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
- fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
- debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
- match (pat.ty.kind(), pat.kind.as_ref()) {
- (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self),
- (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self),
- (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => {
- // Treat string literal patterns as deref patterns to a `str` constant, i.e.
- // `&CONST`. This expands them like other const patterns. This could have been done
- // in `const_to_pat`, but that causes issues with the rest of the matching code.
- let mut new_pat = pat.super_fold_with(self);
- // Make a fake const pattern of type `str` (instead of `&str`). That the carried
- // constant value still knows it is of type `&str`.
- new_pat.ty = t;
- Pat {
- kind: Box::new(PatKind::Deref { subpattern: new_pat }),
- span: pat.span,
- ty: pat.ty,
- }
- }
- _ => pat.super_fold_with(self),
- }
- }
-}
-
-impl<'tcx> Pat<'tcx> {
- pub(super) fn is_wildcard(&self) -> bool {
- matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
- }
-}
-
-/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
-/// works well.
-#[derive(Debug, Clone)]
-struct PatStack<'p, 'tcx> {
- pats: SmallVec<[&'p Pat<'tcx>; 2]>,
- /// Cache for the constructor of the head
- head_ctor: OnceCell<Constructor<'tcx>>,
-}
-
-impl<'p, 'tcx> PatStack<'p, 'tcx> {
- fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
- Self::from_vec(smallvec![pat])
- }
-
- fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
- PatStack { pats: vec, head_ctor: OnceCell::new() }
- }
-
- fn is_empty(&self) -> bool {
- self.pats.is_empty()
- }
-
- fn len(&self) -> usize {
- self.pats.len()
- }
-
- fn head(&self) -> &'p Pat<'tcx> {
- self.pats[0]
- }
-
- fn head_ctor<'a>(&'a self, cx: &MatchCheckCtxt<'p, 'tcx>) -> &'a Constructor<'tcx> {
- self.head_ctor.get_or_init(|| pat_constructor(cx, self.head()))
- }
-
- fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
- self.pats.iter().copied()
- }
-
- // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
- fn expand_or_pat(&self) -> Option<Vec<Self>> {
- if self.is_empty() {
- None
- } else if let PatKind::Or { pats } = &*self.head().kind {
- Some(
- pats.iter()
- .map(|pat| {
- let mut new_patstack = PatStack::from_pattern(pat);
- new_patstack.pats.extend_from_slice(&self.pats[1..]);
- new_patstack
- })
- .collect(),
- )
- } else {
- None
- }
- }
-
- /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
- ///
- /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
- /// fields filled with wild patterns.
- ///
- /// This is roughly the inverse of `Constructor::apply`.
- fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> {
- // We pop the head pattern and push the new fields extracted from the arguments of
- // `self.head()`.
- let new_fields = ctor_wild_subpatterns.replace_with_pattern_arguments(self.head());
- new_fields.push_on_patstack(&self.pats[1..])
- }
-}
-
-impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
- fn default() -> Self {
- Self::from_vec(smallvec![])
- }
-}
-
-impl<'p, 'tcx> PartialEq for PatStack<'p, 'tcx> {
- fn eq(&self, other: &Self) -> bool {
- self.pats == other.pats
- }
-}
-
-impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = &'p Pat<'tcx>>,
- {
- Self::from_vec(iter.into_iter().collect())
- }
-}
-
-/// A 2D matrix.
-#[derive(Clone, PartialEq)]
-struct Matrix<'p, 'tcx> {
- patterns: Vec<PatStack<'p, 'tcx>>,
-}
-
-impl<'p, 'tcx> Matrix<'p, 'tcx> {
- fn empty() -> Self {
- Matrix { patterns: vec![] }
- }
-
- /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
- fn push(&mut self, row: PatStack<'p, 'tcx>) {
- if let Some(rows) = row.expand_or_pat() {
- for row in rows {
- // We recursively expand the or-patterns of the new rows.
- // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`.
- self.push(row)
- }
- } else {
- self.patterns.push(row);
- }
- }
-
- /// Iterate over the first component of each row
- fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
- self.patterns.iter().map(|r| r.head())
- }
-
- /// Iterate over the first constructor of each row
- fn head_ctors<'a>(
- &'a self,
- cx: &'a MatchCheckCtxt<'p, 'tcx>,
- ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'a> + Captures<'p> {
- self.patterns.iter().map(move |r| r.head_ctor(cx))
- }
-
- /// This computes `S(constructor, self)`. See top of the file for explanations.
- fn specialize_constructor(
- &self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- ctor: &Constructor<'tcx>,
- ctor_wild_subpatterns: &Fields<'p, 'tcx>,
- ) -> Matrix<'p, 'tcx> {
- self.patterns
- .iter()
- .filter(|r| ctor.is_covered_by(pcx, r.head_ctor(pcx.cx)))
- .map(|r| r.pop_head_constructor(ctor_wild_subpatterns))
- .collect()
- }
-}
-
-/// Pretty-printer for matrices of patterns, example:
-///
-/// ```text
-/// +++++++++++++++++++++++++++++
-/// + _ + [] +
-/// +++++++++++++++++++++++++++++
-/// + true + [First] +
-/// +++++++++++++++++++++++++++++
-/// + true + [Second(true)] +
-/// +++++++++++++++++++++++++++++
-/// + false + [_] +
-/// +++++++++++++++++++++++++++++
-/// + _ + [_, _, tail @ ..] +
-/// +++++++++++++++++++++++++++++
-/// ```
-impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "\n")?;
-
- let Matrix { patterns: m, .. } = self;
- let pretty_printed_matrix: Vec<Vec<String>> =
- m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect();
-
- let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
- assert!(m.iter().all(|row| row.len() == column_count));
- let column_widths: Vec<usize> = (0..column_count)
- .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0))
- .collect();
-
- let total_width = column_widths.iter().cloned().sum::<usize>() + column_count * 3 + 1;
- let br = "+".repeat(total_width);
- write!(f, "{}\n", br)?;
- for row in pretty_printed_matrix {
- write!(f, "+")?;
- for (column, pat_str) in row.into_iter().enumerate() {
- write!(f, " ")?;
- write!(f, "{:1$}", pat_str, column_widths[column])?;
- write!(f, " +")?;
- }
- write!(f, "\n")?;
- write!(f, "{}\n", br)?;
- }
- Ok(())
- }
-}
-
-impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = PatStack<'p, 'tcx>>,
- {
- let mut matrix = Matrix::empty();
- for x in iter {
- // Using `push` ensures we correctly expand or-patterns.
- matrix.push(x);
- }
- matrix
- }
-}
-
-crate struct MatchCheckCtxt<'a, 'tcx> {
- crate tcx: TyCtxt<'tcx>,
- /// The module in which the match occurs. This is necessary for
- /// checking inhabited-ness of types because whether a type is (visibly)
- /// inhabited can depend on whether it was defined in the current module or
- /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
- /// outside it's module and should not be matchable with an empty match
- /// statement.
- crate module: DefId,
- crate param_env: ty::ParamEnv<'tcx>,
- crate pattern_arena: &'a TypedArena<Pat<'tcx>>,
-}
-
-impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
- fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
- if self.tcx.features().exhaustive_patterns {
- self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env)
- } else {
- false
- }
- }
-
- /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
- fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
- match ty.kind() {
- ty::Adt(def, ..) => {
- def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
- }
- _ => false,
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum SliceKind {
- /// Patterns of length `n` (`[x, y]`).
- FixedLen(u64),
- /// Patterns using the `..` notation (`[x, .., y]`).
- /// Captures any array constructor of `length >= i + j`.
- /// In the case where `array_len` is `Some(_)`,
- /// this indicates that we only care about the first `i` and the last `j` values of the array,
- /// and everything in between is a wildcard `_`.
- VarLen(u64, u64),
-}
-
-impl SliceKind {
- fn arity(self) -> u64 {
- match self {
- FixedLen(length) => length,
- VarLen(prefix, suffix) => prefix + suffix,
- }
- }
-
- /// Whether this pattern includes patterns of length `other_len`.
- fn covers_length(self, other_len: u64) -> bool {
- match self {
- FixedLen(len) => len == other_len,
- VarLen(prefix, suffix) => prefix + suffix <= other_len,
- }
- }
-}
-
-/// A constructor for array and slice patterns.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-struct Slice {
- /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`.
- array_len: Option<u64>,
- /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`.
- kind: SliceKind,
-}
-
-impl Slice {
- fn new(array_len: Option<u64>, kind: SliceKind) -> Self {
- let kind = match (array_len, kind) {
- // If the middle `..` is empty, we effectively have a fixed-length pattern.
- (Some(len), VarLen(prefix, suffix)) if prefix + suffix >= len => FixedLen(len),
- _ => kind,
- };
- Slice { array_len, kind }
- }
-
- fn arity(self) -> u64 {
- 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)],
- };
-
- let head_ctors = pcx.matrix.head_ctors(pcx.cx).filter(|c| !c.is_wildcard());
-
- let mut max_prefix_len = self_prefix;
- let mut max_suffix_len = self_suffix;
- 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);
- }
- }
- } 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 {
- // 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;
- }
-
- let final_slice = VarLen(max_prefix_len, max_suffix_len);
- let final_slice = Slice::new(self.array_len, final_slice);
- 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()
- }
- }
- }
-
- /// See `Constructor::is_covered_by`
- fn is_covered_by(self, other: Self) -> bool {
- other.kind.covers_length(self.arity())
- }
-}
-
-/// A value can be decomposed into a constructor applied to some fields. This struct represents
-/// the constructor. See also `Fields`.
-///
-/// `pat_constructor` retrieves the constructor corresponding to a pattern.
-/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
-/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
-/// `Fields`.
-#[derive(Clone, Debug, PartialEq)]
-enum Constructor<'tcx> {
- /// The constructor for patterns that have a single constructor, like tuples, struct patterns
- /// and fixed-length arrays.
- Single,
- /// Enum variants.
- Variant(DefId),
- /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
- IntRange(IntRange<'tcx>),
- /// Ranges of floating-point literal values (`2.0..=5.2`).
- FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
- /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
- Str(&'tcx ty::Const<'tcx>),
- /// Array and slice patterns.
- Slice(Slice),
- /// Constants that must not be matched structurally. They are treated as black
- /// boxes for the purposes of exhaustiveness: we must not inspect them, and they
- /// don't count towards making a match exhaustive.
- Opaque,
- /// 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,
- /// Wildcard pattern.
- Wildcard,
-}
-
-impl<'tcx> Constructor<'tcx> {
- fn is_wildcard(&self) -> bool {
- matches!(self, Wildcard)
- }
-
- fn as_int_range(&self) -> Option<&IntRange<'tcx>> {
- match self {
- IntRange(range) => Some(range),
- _ => None,
- }
- }
-
- fn as_slice(&self) -> Option<Slice> {
- match self {
- Slice(slice) => Some(*slice),
- _ => None,
- }
- }
-
- fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
- match *self {
- Variant(id) => adt.variant_index_with_id(id),
- Single => {
- assert!(!adt.is_enum());
- VariantIdx::new(0)
- }
- _ => bug!("bad constructor {:?} for adt {:?}", self, adt),
- }
- }
-
- /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual
- /// constructors (like variants, integers or fixed-sized slices). When specializing for these
- /// constructors, we want to be specialising for the actual underlying constructors.
- /// Naively, we would simply return the list of constructors they correspond to. We instead are
- /// more clever: if there are constructors that we know will behave the same wrt the current
- /// matrix, we keep them grouped. For example, all slices of a sufficiently large length
- /// will either be all useful or all non-useful with a given matrix.
- ///
- /// See the branches for details on how the splitting is done.
- ///
- /// 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.
- fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, hir_id: Option<HirId>) -> SmallVec<[Self; 1]> {
- debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
-
- match self {
- Wildcard => Constructor::split_wildcard(pcx),
- // Fast-track if the range is trivial. In particular, we don't do the overlapping
- // ranges check.
- IntRange(ctor_range)
- if ctor_range.treat_exhaustively(pcx.cx.tcx) && !ctor_range.is_singleton() =>
- {
- ctor_range.split(pcx, hir_id)
- }
- Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
- // 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.
- fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
- // This must be kept in sync with `is_covered_by_any`.
- match (self, other) {
- // Wildcards cover anything
- (_, Wildcard) => true,
- // Wildcards are only covered by wildcards
- (Wildcard, _) => false,
-
- (Single, Single) => true,
- (Variant(self_id), Variant(other_id)) => self_id == other_id,
-
- (IntRange(self_range), IntRange(other_range)) => {
- self_range.is_covered_by(pcx, other_range)
- }
- (
- FloatRange(self_from, self_to, self_end),
- FloatRange(other_from, other_to, other_end),
- ) => {
- match (
- compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty),
- compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty),
- ) {
- (Some(to), Some(from)) => {
- (from == Ordering::Greater || from == Ordering::Equal)
- && (to == Ordering::Less
- || (other_end == self_end && to == Ordering::Equal))
- }
- _ => false,
- }
- }
- (Str(self_val), Str(other_val)) => {
- // FIXME: there's probably a more direct way of comparing for equality
- match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty)
- {
- Some(comparison) => comparison == Ordering::Equal,
- None => false,
- }
- }
- (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
-
- // We are trying to inspect an opaque constant. Thus we skip the row.
- (Opaque, _) | (_, Opaque) => false,
- // Only a wildcard pattern can match the special extra constructor.
- (NonExhaustive, _) => false,
-
- _ => span_bug!(
- pcx.span,
- "trying to compare incompatible constructors {:?} and {:?}",
- self,
- other
- ),
- }
- }
-
- /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
- /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
- /// assumed to have been split from a wildcard.
- fn is_covered_by_any<'p>(
- &self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- used_ctors: &[Constructor<'tcx>],
- ) -> bool {
- if used_ctors.is_empty() {
- return false;
- }
-
- // This must be kept in sync with `is_covered_by`.
- match self {
- // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s.
- Single => !used_ctors.is_empty(),
- Variant(_) => used_ctors.iter().any(|c| c == self),
- IntRange(range) => used_ctors
- .iter()
- .filter_map(|c| c.as_int_range())
- .any(|other| range.is_covered_by(pcx, other)),
- Slice(slice) => used_ctors
- .iter()
- .filter_map(|c| c.as_slice())
- .any(|other| slice.is_covered_by(other)),
- // This constructor is never covered by anything else
- NonExhaustive => false,
- Str(..) | FloatRange(..) | Opaque | Wildcard => {
- bug!("found unexpected ctor in all_ctors: {:?}", self)
- }
- }
- }
-
- /// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
- /// must have as many elements as this constructor's arity.
- ///
- /// This is roughly the inverse of `specialize_constructor`.
- ///
- /// Examples:
- /// `self`: `Constructor::Single`
- /// `ty`: `(u32, u32, u32)`
- /// `pats`: `[10, 20, _]`
- /// returns `(10, 20, _)`
- ///
- /// `self`: `Constructor::Variant(Option::Some)`
- /// `ty`: `Option<bool>`
- /// `pats`: `[false]`
- /// returns `Some(false)`
- fn apply<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, fields: Fields<'p, 'tcx>) -> Pat<'tcx> {
- let mut subpatterns = fields.all_patterns();
-
- let pat = match self {
- Single | Variant(_) => match pcx.ty.kind() {
- ty::Adt(..) | ty::Tuple(..) => {
- let subpatterns = subpatterns
- .enumerate()
- .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
- .collect();
-
- if let ty::Adt(adt, substs) = pcx.ty.kind() {
- if adt.is_enum() {
- PatKind::Variant {
- adt_def: adt,
- substs,
- variant_index: self.variant_index_for_adt(adt),
- subpatterns,
- }
- } else {
- PatKind::Leaf { subpatterns }
- }
- } else {
- PatKind::Leaf { subpatterns }
- }
- }
- // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
- // be careful to reconstruct the correct constant pattern here. However a string
- // literal pattern will never be reported as a non-exhaustiveness witness, so we
- // can ignore this issue.
- ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
- ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, pcx.ty),
- _ => PatKind::Wild,
- },
- Slice(slice) => match slice.kind {
- FixedLen(_) => {
- PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
- }
- VarLen(prefix, _) => {
- let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect();
- if slice.array_len.is_some() {
- // Improves diagnostics a bit: if the type is a known-size array, instead
- // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
- // This is incorrect if the size is not known, since `[_, ..]` captures
- // arrays of lengths `>= 1` whereas `[..]` captures any length.
- while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() {
- prefix.pop();
- }
- }
- let suffix: Vec<_> = if slice.array_len.is_some() {
- // Same as above.
- subpatterns.skip_while(Pat::is_wildcard).collect()
- } else {
- subpatterns.collect()
- };
- let wild = Pat::wildcard_from_ty(pcx.ty);
- PatKind::Slice { prefix, slice: Some(wild), suffix }
- }
- },
- &Str(value) => PatKind::Constant { value },
- &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
- IntRange(range) => return range.to_pat(pcx.cx.tcx),
- NonExhaustive => PatKind::Wild,
- 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`"
- ),
- };
-
- Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
- }
-}
-
-/// 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.
-#[derive(Debug, Copy, Clone)]
-enum FilteredField<'p, 'tcx> {
- Kept(&'p Pat<'tcx>),
- Hidden(Ty<'tcx>),
-}
-
-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),
- }
- }
-}
-
-/// 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`.
-///
-/// 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.
-#[derive(Debug, Clone)]
-enum Fields<'p, 'tcx> {
- /// Lists of patterns that don't contain any filtered fields.
- /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and
- /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril)
- /// 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.
- Filtered {
- fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
- kept_count: 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.
- fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
- Fields::Slice(std::slice::from_ref(pat))
- }
-
- /// Convenience; internal use.
- fn wildcards_from_tys(
- cx: &MatchCheckCtxt<'p, 'tcx>,
- tys: impl IntoIterator<Item = Ty<'tcx>>,
- ) -> Self {
- let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
- let pats = cx.pattern_arena.alloc_from_iter(wilds);
- Fields::Slice(pats)
- }
-
- /// Creates a new list of wildcard fields for a given constructor.
- fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
- let ty = pcx.ty;
- let cx = pcx.cx;
- let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));
-
- let ret = match constructor {
- Single | Variant(_) => match ty.kind() {
- ty::Tuple(ref fs) => {
- Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty()))
- }
- ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)),
- ty::Adt(adt, substs) => {
- if adt.is_box() {
- // Use T as the sub pattern type of Box<T>.
- Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
- } else {
- let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
- // Whether we must not match the fields of this variant exhaustively.
- let is_non_exhaustive =
- variant.is_field_list_non_exhaustive() && !adt.did.is_local();
- let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs));
- // In the following cases, we don't need to filter out any fields. This is
- // the vast majority of real cases, since uninhabited fields are uncommon.
- let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive)
- || !field_tys.clone().any(|ty| cx.is_uninhabited(ty));
-
- if has_no_hidden_fields {
- Fields::wildcards_from_tys(cx, field_tys)
- } else {
- let mut kept_count = 0;
- let fields = variant
- .fields
- .iter()
- .map(|field| {
- let ty = field.ty(cx.tcx, substs);
- let is_visible = adt.is_enum()
- || field.vis.is_accessible_from(cx.module, cx.tcx);
- let is_uninhabited = cx.is_uninhabited(ty);
-
- // In the cases of either a `#[non_exhaustive]` field list
- // or a non-public field, we hide uninhabited fields in
- // order not to reveal the uninhabitedness of the whole
- // variant.
- if is_uninhabited && (!is_visible || is_non_exhaustive) {
- FilteredField::Hidden(ty)
- } else {
- kept_count += 1;
- FilteredField::Kept(wildcard_from_ty(ty))
- }
- })
- .collect();
- Fields::Filtered { fields, kept_count }
- }
- }
- }
- _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
- },
- Slice(slice) => match *ty.kind() {
- ty::Slice(ty) | ty::Array(ty, _) => {
- let arity = slice.arity();
- Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
- }
- _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
- },
- Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => {
- Fields::empty()
- }
- };
- debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
- ret
- }
-
- /// 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`.
- fn len(&self) -> usize {
- match self {
- Fields::Slice(pats) => pats.len(),
- Fields::Vec(pats) => pats.len(),
- Fields::Filtered { kept_count, .. } => *kept_count,
- }
- }
-
- /// 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(),
- Fields::Filtered { fields, .. } => {
- // We don't skip any fields here.
- fields.into_iter().map(|p| p.to_pattern()).collect()
- }
- };
- pats.into_iter()
- }
-
- /// Overrides some of the fields with the provided patterns. Exactly like
- /// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
- fn replace_with_fieldpats(
- &self,
- new_pats: impl IntoIterator<Item = &'p FieldPat<'tcx>>,
- ) -> Self {
- self.replace_fields_indexed(
- new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)),
- )
- }
-
- /// 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.
- fn replace_fields_indexed(
- &self,
- new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
- ) -> Self {
- let mut fields = self.clone();
- if let Fields::Slice(pats) = fields {
- fields = Fields::Vec(pats.iter().collect());
- }
-
- match &mut fields {
- Fields::Vec(pats) => {
- for (i, pat) in new_pats {
- pats[i] = pat
- }
- }
- Fields::Filtered { fields, .. } => {
- for (i, pat) in new_pats {
- if let FilteredField::Kept(p) = &mut fields[i] {
- *p = pat
- }
- }
- }
- Fields::Slice(_) => unreachable!(),
- }
- fields
- }
-
- /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the
- /// matrix. There must be `len()` patterns in `pats`.
- fn replace_fields(
- &self,
- cx: &MatchCheckCtxt<'p, 'tcx>,
- pats: impl IntoIterator<Item = Pat<'tcx>>,
- ) -> Self {
- let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
-
- match self {
- Fields::Filtered { fields, kept_count } => {
- let mut pats = pats.iter();
- let mut fields = fields.clone();
- for f in &mut fields {
- if let FilteredField::Kept(p) = f {
- // We take one input pattern for each `Kept` field, in order.
- *p = pats.next().unwrap();
- }
- }
- Fields::Filtered { fields, kept_count: *kept_count }
- }
- _ => Fields::Slice(pats),
- }
- }
-
- /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern
- /// that is compatible with the constructor used to build `self`.
- /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that
- /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern
- /// provided to this function fills some of the fields with non-wildcards.
- /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call
- /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _,
- /// _, _]`.
- /// ```rust
- /// let x: [Option<u8>; 4] = foo();
- /// match x {
- /// [Some(0), ..] => {}
- /// }
- /// ```
- /// This is guaranteed to preserve the number of patterns in `self`.
- fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self {
- match pat.kind.as_ref() {
- PatKind::Deref { subpattern } => {
- assert_eq!(self.len(), 1);
- Fields::from_single_pattern(subpattern)
- }
- PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
- self.replace_with_fieldpats(subpatterns)
- }
- PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => {
- // Number of subpatterns for the constructor
- let ctor_arity = self.len();
-
- // Replace the prefix and the suffix with the given patterns, leaving wildcards in
- // the middle if there was a subslice pattern `..`.
- let prefix = prefix.iter().enumerate();
- let suffix =
- suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p));
- self.replace_fields_indexed(prefix.chain(suffix))
- }
- _ => self.clone(),
- }
- }
-
- fn push_on_patstack(self, stack: &[&'p Pat<'tcx>]) -> PatStack<'p, 'tcx> {
- let pats: SmallVec<_> = match self {
- Fields::Slice(pats) => pats.iter().chain(stack.iter().copied()).collect(),
- Fields::Vec(mut pats) => {
- pats.extend_from_slice(stack);
- pats
- }
- Fields::Filtered { fields, .. } => {
- // We skip hidden fields here
- fields.into_iter().filter_map(|p| p.kept()).chain(stack.iter().copied()).collect()
- }
- };
- PatStack::from_vec(pats)
- }
-}
-
-#[derive(Clone, Debug)]
-crate enum Usefulness<'tcx> {
- /// Carries, for each column in the matrix, a set of sub-branches that have been found to be
- /// unreachable. Used only in the presence of or-patterns, otherwise it stays empty.
- Useful(Vec<FxHashSet<Span>>),
- /// Carries a list of witnesses of non-exhaustiveness.
- UsefulWithWitness(Vec<Witness<'tcx>>),
- NotUseful,
-}
-
-impl<'tcx> Usefulness<'tcx> {
- fn new_useful(preference: WitnessPreference) -> Self {
- match preference {
- ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
- LeaveOutWitness => Useful(vec![]),
- }
- }
-
- fn is_useful(&self) -> bool {
- !matches!(*self, NotUseful)
- }
-
- fn apply_constructor<'p>(
- self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- 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);
- witnesses
- .into_iter()
- .flat_map(|witness| {
- new_patterns.iter().map(move |pat| {
- let mut witness = witness.clone();
- witness.0.push(pat.clone());
- witness
- })
- })
- .collect()
- } else {
- witnesses
- .into_iter()
- .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
- .collect()
- };
- UsefulWithWitness(new_witnesses)
- }
- Useful(mut unreachables) => {
- if !unreachables.is_empty() {
- // When we apply a constructor, there are `arity` columns of the matrix that
- // corresponded to its arguments. All the unreachables found in these columns
- // will, after `apply`, come from the first column. So we take the union of all
- // the corresponding sets and put them in the first column.
- // Note that `arity` may be 0, in which case we just push a new empty set.
- let len = unreachables.len();
- let arity = ctor_wild_subpatterns.len();
- let mut unioned = FxHashSet::default();
- for set in unreachables.drain((len - arity)..) {
- unioned.extend(set)
- }
- unreachables.push(unioned);
- }
- Useful(unreachables)
- }
- x => x,
- }
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-enum WitnessPreference {
- ConstructWitness,
- LeaveOutWitness,
-}
-
-#[derive(Copy, Clone)]
-struct PatCtxt<'a, 'p, 'tcx> {
- cx: &'a MatchCheckCtxt<'p, 'tcx>,
- /// Current state of the matrix.
- matrix: &'a Matrix<'p, 'tcx>,
- /// Type of the current column under investigation.
- ty: Ty<'tcx>,
- /// Span of the current pattern under investigation.
- span: Span,
- /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a
- /// subpattern.
- is_top_level: bool,
-}
-
-/// A witness of non-exhaustiveness for error reporting, represented
-/// as a list of patterns (in reverse order of construction) with
-/// wildcards inside to represent elements that can take any inhabitant
-/// of the type as a value.
-///
-/// A witness against a list of patterns should have the same types
-/// and length as the pattern matched against. Because Rust `match`
-/// is always against a single pattern, at the end the witness will
-/// have length 1, but in the middle of the algorithm, it can contain
-/// multiple patterns.
-///
-/// For example, if we are constructing a witness for the match against
-///
-/// ```
-/// struct Pair(Option<(u32, u32)>, bool);
-///
-/// match (p: Pair) {
-/// Pair(None, _) => {}
-/// Pair(_, false) => {}
-/// }
-/// ```
-///
-/// 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])`
-/// 4. Apply the `Pair` constructor to the witnesses
-/// `Witness(vec![Pair(Some(_), true)])`
-///
-/// The final `Pair(Some(_), true)` is then the resulting witness.
-#[derive(Clone, Debug)]
-crate struct Witness<'tcx>(Vec<Pat<'tcx>>);
-
-impl<'tcx> Witness<'tcx> {
- /// Asserts that the witness contains a single pattern, and returns it.
- fn single_pattern(self) -> Pat<'tcx> {
- assert_eq!(self.0.len(), 1);
- self.0.into_iter().next().unwrap()
- }
-
- /// Constructs a partial witness for a pattern given a list of
- /// patterns expanded by the specialization step.
- ///
- /// When a pattern P is discovered to be useful, this function is used bottom-up
- /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset
- /// of values, V, where each value in that set is not covered by any previously
- /// used patterns and is covered by the pattern P'. Examples:
- ///
- /// left_ty: tuple of 3 elements
- /// pats: [10, 20, _] => (10, 20, _)
- ///
- /// left_ty: struct X { a: (bool, &'static str), b: usize}
- /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
- fn apply_constructor<'p>(
- mut self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- ctor: &Constructor<'tcx>,
- ctor_wild_subpatterns: &Fields<'p, 'tcx>,
- ) -> Self {
- let pat = {
- let len = self.0.len();
- let arity = ctor_wild_subpatterns.len();
- let pats = self.0.drain((len - arity)..).rev();
- let fields = ctor_wild_subpatterns.replace_fields(pcx.cx, pats);
- ctor.apply(pcx, fields)
- };
-
- self.0.push(pat);
-
- 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.
-///
-/// 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, pcx.span)
- .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],
- }
-}
-
-/// An inclusive interval, used for precise integer exhaustiveness checking.
-/// `IntRange`s always store a contiguous range. This means that values are
-/// encoded such that `0` encodes the minimum value for the integer,
-/// regardless of the signedness.
-/// For example, the pattern `-128..=127i8` is encoded as `0..=255`.
-/// This makes comparisons and arithmetic on interval endpoints much more
-/// straightforward. See `signed_bias` for details.
-///
-/// `IntRange` is never used to encode an empty range or a "range" that wraps
-/// around the (offset) space: i.e., `range.lo <= range.hi`.
-#[derive(Clone, Debug)]
-struct IntRange<'tcx> {
- range: RangeInclusive<u128>,
- ty: Ty<'tcx>,
- span: Span,
-}
-
-impl<'tcx> IntRange<'tcx> {
- #[inline]
- fn is_integral(ty: Ty<'_>) -> bool {
- matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
- }
-
- fn is_singleton(&self) -> bool {
- self.range.start() == self.range.end()
- }
-
- fn boundaries(&self) -> (u128, u128) {
- (*self.range.start(), *self.range.end())
- }
-
- /// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching` feature
- /// is enabled.
- fn treat_exhaustively(&self, tcx: TyCtxt<'tcx>) -> bool {
- !self.ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching
- }
-
- #[inline]
- fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
- match *ty.kind() {
- ty::Bool => Some((Size::from_bytes(1), 0)),
- ty::Char => Some((Size::from_bytes(4), 0)),
- ty::Int(ity) => {
- let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
- Some((size, 1u128 << (size.bits() as u128 - 1)))
- }
- ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)),
- _ => None,
- }
- }
-
- #[inline]
- fn from_const(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- value: &Const<'tcx>,
- span: Span,
- ) -> Option<IntRange<'tcx>> {
- if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
- let ty = value.ty;
- let val = (|| {
- if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val {
- // For this specific pattern we can skip a lot of effort and go
- // straight to the result, after doing a bit of checking. (We
- // could remove this branch and just fall through, which
- // is more general but much slower.)
- if let Ok(bits) = scalar.to_bits_or_ptr(target_size, &tcx) {
- return Some(bits);
- }
- }
- // This is a more general form of the previous case.
- value.try_eval_bits(tcx, param_env, ty)
- })()?;
- let val = val ^ bias;
- Some(IntRange { range: val..=val, ty, span })
- } else {
- None
- }
- }
-
- #[inline]
- fn from_range(
- tcx: TyCtxt<'tcx>,
- lo: u128,
- hi: u128,
- ty: Ty<'tcx>,
- end: &RangeEnd,
- span: Span,
- ) -> Option<IntRange<'tcx>> {
- if Self::is_integral(ty) {
- // Perform a shift if the underlying types are signed,
- // which makes the interval arithmetic simpler.
- let bias = IntRange::signed_bias(tcx, ty);
- let (lo, hi) = (lo ^ bias, hi ^ bias);
- let offset = (*end == RangeEnd::Excluded) as u128;
- if lo > hi || (lo == hi && *end == RangeEnd::Excluded) {
- // This should have been caught earlier by E0030.
- bug!("malformed range pattern: {}..={}", lo, (hi - offset));
- }
- Some(IntRange { range: lo..=(hi - offset), ty, span })
- } else {
- None
- }
- }
-
- // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
- fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 {
- match *ty.kind() {
- ty::Int(ity) => {
- let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
- 1u128 << (bits - 1)
- }
- _ => 0,
- }
- }
-
- fn is_subrange(&self, other: &Self) -> bool {
- other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
- }
-
- fn intersection(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Option<Self> {
- let ty = self.ty;
- let (lo, hi) = self.boundaries();
- let (other_lo, other_hi) = other.boundaries();
- if self.treat_exhaustively(tcx) {
- if lo <= other_hi && other_lo <= hi {
- let span = other.span;
- Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span })
- } else {
- None
- }
- } else {
- // If the range should not be treated exhaustively, fallback to checking for inclusion.
- if self.is_subrange(other) { Some(self.clone()) } else { None }
- }
- }
-
- fn suspicious_intersection(&self, other: &Self) -> bool {
- // `false` in the following cases:
- // 1 ---- // 1 ---------- // 1 ---- // 1 ----
- // 2 ---------- // 2 ---- // 2 ---- // 2 ----
- //
- // The following are currently `false`, but could be `true` in the future (#64007):
- // 1 --------- // 1 ---------
- // 2 ---------- // 2 ----------
- //
- // `true` in the following cases:
- // 1 ------- // 1 -------
- // 2 -------- // 2 -------
- let (lo, hi) = self.boundaries();
- let (other_lo, other_hi) = other.boundaries();
- lo == other_hi || hi == other_lo
- }
-
- fn to_pat(&self, tcx: TyCtxt<'tcx>) -> Pat<'tcx> {
- let (lo, hi) = self.boundaries();
-
- let bias = IntRange::signed_bias(tcx, self.ty);
- let (lo, hi) = (lo ^ bias, hi ^ bias);
-
- let ty = ty::ParamEnv::empty().and(self.ty);
- let lo_const = ty::Const::from_bits(tcx, lo, ty);
- let hi_const = ty::Const::from_bits(tcx, hi, ty);
-
- let kind = if lo == hi {
- PatKind::Constant { value: lo_const }
- } else {
- PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
- };
-
- // This is a brand new pattern, so we don't reuse `self.span`.
- Pat { ty: self.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>(
- &self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
- hir_id: Option<HirId>,
- ) -> SmallVec<[Constructor<'tcx>; 1]> {
- let ty = pcx.ty;
-
- /// 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,
- }
-
- // 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()
- }
-
- // 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.patterns.get(0).map(|r| r.len()).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(pcx.cx)
- .filter_map(|ctor| ctor.as_int_range())
- .filter_map(|range| {
- let intersection = self.intersection(pcx.cx.tcx, &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 (10u8, true) {
- // (0 ..= 125, false) => {}
- // (126 ..= 255, false) => {}
- // (0 ..= 255, true) => {}
- // }
- overlaps.push(range.clone());
- }
- 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.cx.tcx, hir_id, ty, 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, ty, span: pcx.span })
- .map(IntRange)
- .collect()
- }
-
- fn lint_overlapping_patterns(
- &self,
- tcx: TyCtxt<'tcx>,
- hir_id: Option<HirId>,
- ty: Ty<'tcx>,
- overlaps: Vec<IntRange<'tcx>>,
- ) {
- if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
- tcx.struct_span_lint_hir(
- lint::builtin::OVERLAPPING_PATTERNS,
- hir_id,
- self.span,
- |lint| {
- let mut err = lint.build("multiple patterns covering the same range");
- err.span_label(self.span, "overlapping patterns");
- for int_range in overlaps {
- // Use the real type for user display of the ranges:
- err.span_label(
- int_range.span,
- &format!(
- "this range overlaps on `{}`",
- IntRange { range: int_range.range, ty, span: DUMMY_SP }.to_pat(tcx),
- ),
- );
- }
- err.emit();
- },
- );
- }
- }
-
- /// See `Constructor::is_covered_by`
- fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
- if self.intersection(pcx.cx.tcx, other).is_some() {
- // Constructor splitting should ensure that all intersections we encounter are actually
- // inclusions.
- assert!(self.is_subrange(other));
- true
- } else {
- false
- }
- }
-}
-
-/// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
-impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
- fn eq(&self, other: &Self) -> bool {
- self.range == other.range && self.ty == other.ty
- }
-}
-
-// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
-#[derive(Debug)]
-struct MissingConstructors<'tcx> {
- all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
- used_ctors: Vec<Constructor<'tcx>>,
-}
-
-impl<'tcx> MissingConstructors<'tcx> {
- 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();
-
- MissingConstructors { all_ctors, used_ctors }
- }
-
- fn is_empty<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> bool {
- self.iter(pcx).next().is_none()
- }
-
- /// Iterate over all_ctors \ used_ctors
- fn iter<'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))
- }
-
- /// 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.
- 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| {
- let fields = Fields::wildcards(pcx, &missing_ctor);
- missing_ctor.apply(pcx, fields)
- })
- .collect()
- }
- }
-}
-
-/// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
-/// The algorithm from the paper has been modified to correctly handle empty
-/// types. The changes are:
-/// (0) We don't exit early if the pattern matrix has zero rows. We just
-/// continue to recurse over columns.
-/// (1) all_constructors will only return constructors that are statically
-/// possible. E.g., it will only return `Ok` for `Result<T, !>`.
-///
-/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
-/// to a set of such vectors `m` - this is defined as there being a set of
-/// inputs that will match `v` but not any of the sets in `m`.
-///
-/// All the patterns at each column of the `matrix ++ v` matrix must have the same type.
-///
-/// This is used both for reachability checking (if a pattern isn't useful in
-/// relation to preceding patterns, it is not reachable) and exhaustiveness
-/// checking (if a wildcard pattern is useful in relation to a matrix, the
-/// matrix isn't exhaustive).
-///
-/// `is_under_guard` is used to inform if the pattern has a guard. If it
-/// has one it must not be inserted into the matrix. This shouldn't be
-/// relied on for soundness.
-fn is_useful<'p, 'tcx>(
- cx: &MatchCheckCtxt<'p, 'tcx>,
- matrix: &Matrix<'p, 'tcx>,
- v: &PatStack<'p, 'tcx>,
- witness_preference: WitnessPreference,
- hir_id: HirId,
- is_under_guard: bool,
- is_top_level: bool,
-) -> Usefulness<'tcx> {
- let Matrix { patterns: rows, .. } = matrix;
- debug!("is_useful({:#?}, {:#?})", matrix, v);
-
- // The base case. We are pattern-matching on () and the return value is
- // based on whether our matrix has a row or not.
- // NOTE: This could potentially be optimized by checking rows.is_empty()
- // first and then, if v is non-empty, the return value is based on whether
- // the type of the tuple we're checking is inhabited or not.
- if v.is_empty() {
- return if rows.is_empty() {
- Usefulness::new_useful(witness_preference)
- } else {
- NotUseful
- };
- };
-
- assert!(rows.iter().all(|r| r.len() == v.len()));
-
- // If the first pattern is an or-pattern, expand it.
- if let Some(vs) = v.expand_or_pat() {
- // We expand the or pattern, trying each of its branches in turn and keeping careful track
- // of possible unreachable sub-branches.
- //
- // If two branches have detected some unreachable sub-branches, we need to be careful. If
- // they were detected in columns that are not the current one, we want to keep only the
- // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last
- // `true` is unreachable in the second branch of the first or-pattern, but not otherwise.
- // Therefore we don't want to lint that it is unreachable.
- //
- // ```
- // match (true, true) {
- // (true, true) => {}
- // (false | true, false | true) => {}
- // }
- // ```
- // If however the sub-branches come from the current column, they come from the inside of
- // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want
- // to lint that the last `false` is unreachable.
- // ```
- // match None {
- // Some(false) => {}
- // None | Some(true | false) => {}
- // }
- // ```
-
- let mut matrix = matrix.clone();
- // We keep track of sub-branches separately depending on whether they come from this column
- // or from others.
- let mut unreachables_this_column: FxHashSet<Span> = FxHashSet::default();
- let mut unreachables_other_columns: Vec<FxHashSet<Span>> = Vec::default();
- // Whether at least one branch is reachable.
- let mut any_is_useful = false;
-
- for v in vs {
- let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
- match res {
- Useful(unreachables) => {
- if let Some((this_column, other_columns)) = unreachables.split_last() {
- // We keep the union of unreachables found in the first column.
- unreachables_this_column.extend(this_column);
- // We keep the intersection of unreachables found in other columns.
- if unreachables_other_columns.is_empty() {
- unreachables_other_columns = other_columns.to_vec();
- } else {
- unreachables_other_columns = unreachables_other_columns
- .into_iter()
- .zip(other_columns)
- .map(|(x, y)| x.intersection(&y).copied().collect())
- .collect();
- }
- }
- any_is_useful = true;
- }
- NotUseful => {
- unreachables_this_column.insert(v.head().span);
- }
- UsefulWithWitness(_) => bug!(
- "encountered or-pat in the expansion of `_` during exhaustiveness checking"
- ),
- }
-
- // If pattern has a guard don't add it to the matrix.
- if !is_under_guard {
- // We push the already-seen patterns into the matrix in order to detect redundant
- // branches like `Some(_) | Some(0)`.
- matrix.push(v);
- }
- }
-
- return if any_is_useful {
- let mut unreachables = if unreachables_other_columns.is_empty() {
- let n_columns = v.len();
- (0..n_columns - 1).map(|_| FxHashSet::default()).collect()
- } else {
- unreachables_other_columns
- };
- unreachables.push(unreachables_this_column);
- Useful(unreachables)
- } else {
- NotUseful
- };
- }
-
- // 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 };
-
- debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
-
- let ret = v
- .head_ctor(cx)
- .split(pcx, Some(hir_id))
- .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 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)
- })
- .find(|result| result.is_useful())
- .unwrap_or(NotUseful);
- debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
- ret
-}
-
-/// Determines the constructor that the given pattern can be specialized to.
-/// Returns `None` in case of a catch-all, which can't be specialized.
-fn pat_constructor<'p, 'tcx>(
- cx: &MatchCheckCtxt<'p, 'tcx>,
- pat: &'p Pat<'tcx>,
-) -> Constructor<'tcx> {
- match pat.kind.as_ref() {
- PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
- PatKind::Binding { .. } | PatKind::Wild => Wildcard,
- PatKind::Leaf { .. } | PatKind::Deref { .. } => Single,
- &PatKind::Variant { adt_def, variant_index, .. } => {
- Variant(adt_def.variants[variant_index].def_id)
- }
- PatKind::Constant { value } => {
- if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value, pat.span) {
- IntRange(int_range)
- } else {
- match pat.ty.kind() {
- ty::Float(_) => FloatRange(value, value, RangeEnd::Included),
- // In `expand_pattern`, we convert string literals to `&CONST` patterns with
- // `CONST` a pattern of type `str`. In truth this contains a constant of type
- // `&str`.
- ty::Str => Str(value),
- // All constants that can be structurally matched have already been expanded
- // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
- // opaque.
- _ => Opaque,
- }
- }
- }
- &PatKind::Range(PatRange { lo, hi, end }) => {
- let ty = lo.ty;
- if let Some(int_range) = IntRange::from_range(
- cx.tcx,
- lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
- hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
- ty,
- &end,
- pat.span,
- ) {
- IntRange(int_range)
- } else {
- FloatRange(lo, hi, end)
- }
- }
- PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
- let array_len = match pat.ty.kind() {
- ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)),
- ty::Slice(_) => None,
- _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
- };
- let prefix = prefix.len() as u64;
- let suffix = suffix.len() as u64;
- let kind =
- if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
- Slice(Slice::new(array_len, kind))
- }
- PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
- }
-}
-
-/// The arm of a match expression.
-#[derive(Clone, Copy)]
-crate struct MatchArm<'p, 'tcx> {
- /// The pattern must have been lowered through `MatchVisitor::lower_pattern`.
- crate pat: &'p super::Pat<'tcx>,
- crate hir_id: HirId,
- crate has_guard: bool,
-}
-
-/// The output of checking a match for exhaustiveness and arm reachability.
-crate struct UsefulnessReport<'p, 'tcx> {
- /// For each arm of the input, whether that arm is reachable after the arms above it.
- crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Usefulness<'tcx>)>,
- /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
- /// exhaustiveness.
- crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>,
-}
-
-/// 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`.
-crate fn compute_match_usefulness<'p, 'tcx>(
- cx: &MatchCheckCtxt<'p, 'tcx>,
- arms: &[MatchArm<'p, 'tcx>],
- scrut_hir_id: HirId,
- scrut_ty: Ty<'tcx>,
-) -> UsefulnessReport<'p, 'tcx> {
- let mut matrix = Matrix::empty();
- let arm_usefulness: Vec<_> = arms
- .iter()
- .copied()
- .map(|arm| {
- let v = PatStack::from_pattern(arm.pat);
- let usefulness =
- is_useful(cx, &matrix, &v, LeaveOutWitness, arm.hir_id, arm.has_guard, true);
- if !arm.has_guard {
- matrix.push(v);
- }
- (arm, usefulness)
- })
- .collect();
-
- let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty));
- let v = PatStack::from_pattern(wild_pattern);
- let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
- let non_exhaustiveness_witnesses = match usefulness {
- NotUseful => vec![], // Wildcard pattern isn't useful, so the match is exhaustive.
- UsefulWithWitness(pats) => {
- if pats.is_empty() {
- bug!("Exhaustiveness check returned no witnesses")
- } else {
- pats.into_iter().map(|w| w.single_pattern()).collect()
- }
- }
- Useful(_) => bug!(),
- };
- UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
-}
-use super::_match::Usefulness::*;
-use super::_match::{
+use super::usefulness::Usefulness::*;
+use super::usefulness::{
compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, UsefulnessReport,
};
use super::{PatCtxt, PatKind, PatternError};
--- /dev/null
+//! 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.
+use self::Constructor::*;
+use self::SliceKind::*;
+
+use super::compare_const_vals;
+use super::usefulness::{MatchCheckCtxt, PatCtxt};
+use super::{FieldPat, Pat, PatKind, PatRange};
+
+use rustc_data_structures::captures::Captures;
+use rustc_index::vec::Idx;
+
+use rustc_attr::{SignedInt, UnsignedInt};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{HirId, RangeEnd};
+use rustc_middle::mir::interpret::ConstValue;
+use rustc_middle::mir::Field;
+use rustc_middle::ty::layout::IntegerExt;
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
+use rustc_session::lint;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi::{Integer, Size, VariantIdx};
+
+use smallvec::{smallvec, SmallVec};
+use std::cmp::{self, max, min, Ordering};
+use std::iter::IntoIterator;
+use std::ops::RangeInclusive;
+
+/// An inclusive interval, used for precise integer exhaustiveness checking.
+/// `IntRange`s always store a contiguous range. This means that values are
+/// encoded such that `0` encodes the minimum value for the integer,
+/// regardless of the signedness.
+/// For example, the pattern `-128..=127i8` is encoded as `0..=255`.
+/// This makes comparisons and arithmetic on interval endpoints much more
+/// straightforward. See `signed_bias` for details.
+///
+/// `IntRange` is never used to encode an empty range or a "range" that wraps
+/// around the (offset) space: i.e., `range.lo <= range.hi`.
+#[derive(Clone, Debug)]
+pub(super) struct IntRange<'tcx> {
+ range: RangeInclusive<u128>,
+ ty: Ty<'tcx>,
+ span: Span,
+}
+
+impl<'tcx> IntRange<'tcx> {
+ #[inline]
+ fn is_integral(ty: Ty<'_>) -> bool {
+ matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
+ }
+
+ fn is_singleton(&self) -> bool {
+ self.range.start() == self.range.end()
+ }
+
+ fn boundaries(&self) -> (u128, u128) {
+ (*self.range.start(), *self.range.end())
+ }
+
+ /// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching` feature
+ /// is enabled.
+ fn treat_exhaustively(&self, tcx: TyCtxt<'tcx>) -> bool {
+ !self.ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching
+ }
+
+ #[inline]
+ fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
+ match *ty.kind() {
+ ty::Bool => Some((Size::from_bytes(1), 0)),
+ ty::Char => Some((Size::from_bytes(4), 0)),
+ ty::Int(ity) => {
+ let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+ Some((size, 1u128 << (size.bits() as u128 - 1)))
+ }
+ ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ fn from_const(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: &Const<'tcx>,
+ span: Span,
+ ) -> Option<IntRange<'tcx>> {
+ if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
+ let ty = value.ty;
+ let val = (|| {
+ if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val {
+ // For this specific pattern we can skip a lot of effort and go
+ // straight to the result, after doing a bit of checking. (We
+ // could remove this branch and just fall through, which
+ // is more general but much slower.)
+ if let Ok(bits) = scalar.to_bits_or_ptr(target_size, &tcx) {
+ return Some(bits);
+ }
+ }
+ // This is a more general form of the previous case.
+ value.try_eval_bits(tcx, param_env, ty)
+ })()?;
+ let val = val ^ bias;
+ Some(IntRange { range: val..=val, ty, span })
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn from_range(
+ tcx: TyCtxt<'tcx>,
+ lo: u128,
+ hi: u128,
+ ty: Ty<'tcx>,
+ end: &RangeEnd,
+ span: Span,
+ ) -> Option<IntRange<'tcx>> {
+ if Self::is_integral(ty) {
+ // Perform a shift if the underlying types are signed,
+ // which makes the interval arithmetic simpler.
+ let bias = IntRange::signed_bias(tcx, ty);
+ let (lo, hi) = (lo ^ bias, hi ^ bias);
+ let offset = (*end == RangeEnd::Excluded) as u128;
+ if lo > hi || (lo == hi && *end == RangeEnd::Excluded) {
+ // This should have been caught earlier by E0030.
+ bug!("malformed range pattern: {}..={}", lo, (hi - offset));
+ }
+ Some(IntRange { range: lo..=(hi - offset), ty, span })
+ } else {
+ None
+ }
+ }
+
+ // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
+ fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 {
+ match *ty.kind() {
+ ty::Int(ity) => {
+ let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
+ 1u128 << (bits - 1)
+ }
+ _ => 0,
+ }
+ }
+
+ fn is_subrange(&self, other: &Self) -> bool {
+ other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
+ }
+
+ fn intersection(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Option<Self> {
+ let ty = self.ty;
+ let (lo, hi) = self.boundaries();
+ let (other_lo, other_hi) = other.boundaries();
+ if self.treat_exhaustively(tcx) {
+ if lo <= other_hi && other_lo <= hi {
+ let span = other.span;
+ Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span })
+ } else {
+ None
+ }
+ } else {
+ // If the range should not be treated exhaustively, fallback to checking for inclusion.
+ if self.is_subrange(other) { Some(self.clone()) } else { None }
+ }
+ }
+
+ fn suspicious_intersection(&self, other: &Self) -> bool {
+ // `false` in the following cases:
+ // 1 ---- // 1 ---------- // 1 ---- // 1 ----
+ // 2 ---------- // 2 ---- // 2 ---- // 2 ----
+ //
+ // The following are currently `false`, but could be `true` in the future (#64007):
+ // 1 --------- // 1 ---------
+ // 2 ---------- // 2 ----------
+ //
+ // `true` in the following cases:
+ // 1 ------- // 1 -------
+ // 2 -------- // 2 -------
+ let (lo, hi) = self.boundaries();
+ let (other_lo, other_hi) = other.boundaries();
+ lo == other_hi || hi == other_lo
+ }
+
+ fn to_pat(&self, tcx: TyCtxt<'tcx>) -> Pat<'tcx> {
+ let (lo, hi) = self.boundaries();
+
+ let bias = IntRange::signed_bias(tcx, self.ty);
+ let (lo, hi) = (lo ^ bias, hi ^ bias);
+
+ let ty = ty::ParamEnv::empty().and(self.ty);
+ let lo_const = ty::Const::from_bits(tcx, lo, ty);
+ let hi_const = ty::Const::from_bits(tcx, hi, ty);
+
+ let kind = if lo == hi {
+ PatKind::Constant { value: lo_const }
+ } else {
+ PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
+ };
+
+ // This is a brand new pattern, so we don't reuse `self.span`.
+ Pat { ty: self.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>(
+ &self,
+ pcx: PatCtxt<'_, 'p, 'tcx>,
+ hir_id: Option<HirId>,
+ ) -> SmallVec<[Constructor<'tcx>; 1]> {
+ let ty = pcx.ty;
+
+ /// 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,
+ }
+
+ // 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()
+ }
+
+ // 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(pcx.cx)
+ .filter_map(|ctor| ctor.as_int_range())
+ .filter_map(|range| {
+ let intersection = self.intersection(pcx.cx.tcx, &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 (10u8, true) {
+ // (0 ..= 125, false) => {}
+ // (126 ..= 255, false) => {}
+ // (0 ..= 255, true) => {}
+ // }
+ overlaps.push(range.clone());
+ }
+ 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.cx.tcx, hir_id, ty, 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, ty, span: pcx.span })
+ .map(IntRange)
+ .collect()
+ }
+
+ fn lint_overlapping_patterns(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ hir_id: Option<HirId>,
+ ty: Ty<'tcx>,
+ overlaps: Vec<IntRange<'tcx>>,
+ ) {
+ if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
+ tcx.struct_span_lint_hir(
+ lint::builtin::OVERLAPPING_PATTERNS,
+ hir_id,
+ self.span,
+ |lint| {
+ let mut err = lint.build("multiple patterns covering the same range");
+ err.span_label(self.span, "overlapping patterns");
+ for int_range in overlaps {
+ // Use the real type for user display of the ranges:
+ err.span_label(
+ int_range.span,
+ &format!(
+ "this range overlaps on `{}`",
+ IntRange { range: int_range.range, ty, span: DUMMY_SP }.to_pat(tcx),
+ ),
+ );
+ }
+ err.emit();
+ },
+ );
+ }
+ }
+
+ /// See `Constructor::is_covered_by`
+ fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
+ if self.intersection(pcx.cx.tcx, other).is_some() {
+ // Constructor splitting should ensure that all intersections we encounter are actually
+ // inclusions.
+ assert!(self.is_subrange(other));
+ true
+ } else {
+ false
+ }
+ }
+}
+
+/// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
+impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
+ fn eq(&self, other: &Self) -> bool {
+ self.range == other.range && self.ty == other.ty
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum SliceKind {
+ /// Patterns of length `n` (`[x, y]`).
+ FixedLen(u64),
+ /// Patterns using the `..` notation (`[x, .., y]`).
+ /// Captures any array constructor of `length >= i + j`.
+ /// In the case where `array_len` is `Some(_)`,
+ /// this indicates that we only care about the first `i` and the last `j` values of the array,
+ /// and everything in between is a wildcard `_`.
+ VarLen(u64, u64),
+}
+
+impl SliceKind {
+ fn arity(self) -> u64 {
+ match self {
+ FixedLen(length) => length,
+ VarLen(prefix, suffix) => prefix + suffix,
+ }
+ }
+
+ /// Whether this pattern includes patterns of length `other_len`.
+ fn covers_length(self, other_len: u64) -> bool {
+ match self {
+ FixedLen(len) => len == other_len,
+ VarLen(prefix, suffix) => prefix + suffix <= other_len,
+ }
+ }
+}
+
+/// A constructor for array and slice patterns.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(super) struct Slice {
+ /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`.
+ array_len: Option<u64>,
+ /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`.
+ kind: SliceKind,
+}
+
+impl Slice {
+ fn new(array_len: Option<u64>, kind: SliceKind) -> Self {
+ let kind = match (array_len, kind) {
+ // If the middle `..` is empty, we effectively have a fixed-length pattern.
+ (Some(len), VarLen(prefix, suffix)) if prefix + suffix >= len => FixedLen(len),
+ _ => kind,
+ };
+ Slice { array_len, kind }
+ }
+
+ fn arity(self) -> u64 {
+ 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)],
+ };
+
+ let head_ctors = pcx.matrix.head_ctors(pcx.cx).filter(|c| !c.is_wildcard());
+
+ let mut max_prefix_len = self_prefix;
+ let mut max_suffix_len = self_suffix;
+ 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);
+ }
+ }
+ } 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 {
+ // 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;
+ }
+
+ let final_slice = VarLen(max_prefix_len, max_suffix_len);
+ let final_slice = Slice::new(self.array_len, final_slice);
+ 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()
+ }
+ }
+ }
+
+ /// See `Constructor::is_covered_by`
+ fn is_covered_by(self, other: Self) -> bool {
+ other.kind.covers_length(self.arity())
+ }
+}
+
+/// A value can be decomposed into a constructor applied to some fields. This struct represents
+/// the constructor. See also `Fields`.
+///
+/// `pat_constructor` retrieves the constructor corresponding to a pattern.
+/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
+/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
+/// `Fields`.
+#[derive(Clone, Debug, PartialEq)]
+pub(super) enum Constructor<'tcx> {
+ /// The constructor for patterns that have a single constructor, like tuples, struct patterns
+ /// and fixed-length arrays.
+ Single,
+ /// Enum variants.
+ Variant(DefId),
+ /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
+ IntRange(IntRange<'tcx>),
+ /// Ranges of floating-point literal values (`2.0..=5.2`).
+ FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+ /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
+ Str(&'tcx ty::Const<'tcx>),
+ /// Array and slice patterns.
+ Slice(Slice),
+ /// Constants that must not be matched structurally. They are treated as black
+ /// boxes for the purposes of exhaustiveness: we must not inspect them, and they
+ /// don't count towards making a match exhaustive.
+ Opaque,
+ /// 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,
+ /// Wildcard pattern.
+ Wildcard,
+}
+
+impl<'tcx> Constructor<'tcx> {
+ pub(super) fn is_wildcard(&self) -> bool {
+ matches!(self, Wildcard)
+ }
+
+ fn as_int_range(&self) -> Option<&IntRange<'tcx>> {
+ match self {
+ IntRange(range) => Some(range),
+ _ => None,
+ }
+ }
+
+ fn as_slice(&self) -> Option<Slice> {
+ match self {
+ Slice(slice) => Some(*slice),
+ _ => None,
+ }
+ }
+
+ fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
+ match *self {
+ Variant(id) => adt.variant_index_with_id(id),
+ Single => {
+ assert!(!adt.is_enum());
+ VariantIdx::new(0)
+ }
+ _ => bug!("bad constructor {:?} for adt {:?}", self, adt),
+ }
+ }
+
+ /// Determines the constructor that the given pattern can be specialized to.
+ pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>) -> Self {
+ match pat.kind.as_ref() {
+ PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
+ PatKind::Binding { .. } | PatKind::Wild => Wildcard,
+ PatKind::Leaf { .. } | PatKind::Deref { .. } => Single,
+ &PatKind::Variant { adt_def, variant_index, .. } => {
+ Variant(adt_def.variants[variant_index].def_id)
+ }
+ PatKind::Constant { value } => {
+ if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value, pat.span)
+ {
+ IntRange(int_range)
+ } else {
+ match pat.ty.kind() {
+ ty::Float(_) => FloatRange(value, value, RangeEnd::Included),
+ // In `expand_pattern`, we convert string literals to `&CONST` patterns with
+ // `CONST` a pattern of type `str`. In truth this contains a constant of type
+ // `&str`.
+ ty::Str => Str(value),
+ // All constants that can be structurally matched have already been expanded
+ // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
+ // opaque.
+ _ => Opaque,
+ }
+ }
+ }
+ &PatKind::Range(PatRange { lo, hi, end }) => {
+ let ty = lo.ty;
+ if let Some(int_range) = IntRange::from_range(
+ cx.tcx,
+ lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
+ hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
+ ty,
+ &end,
+ pat.span,
+ ) {
+ IntRange(int_range)
+ } else {
+ FloatRange(lo, hi, end)
+ }
+ }
+ PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
+ let array_len = match pat.ty.kind() {
+ ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)),
+ ty::Slice(_) => None,
+ _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
+ };
+ let prefix = prefix.len() as u64;
+ let suffix = suffix.len() as u64;
+ let kind = if slice.is_some() {
+ VarLen(prefix, suffix)
+ } else {
+ FixedLen(prefix + suffix)
+ };
+ Slice(Slice::new(array_len, kind))
+ }
+ PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
+ }
+ }
+
+ /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual
+ /// constructors (like variants, integers or fixed-sized slices). When specializing for these
+ /// constructors, we want to be specialising for the actual underlying constructors.
+ /// Naively, we would simply return the list of constructors they correspond to. We instead are
+ /// more clever: if there are constructors that we know will behave the same wrt the current
+ /// matrix, we keep them grouped. For example, all slices of a sufficiently large length
+ /// will either be all useful or all non-useful with a given matrix.
+ ///
+ /// See the branches for details on how the splitting is done.
+ ///
+ /// 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>(
+ &self,
+ pcx: PatCtxt<'_, 'p, 'tcx>,
+ hir_id: Option<HirId>,
+ ) -> SmallVec<[Self; 1]> {
+ debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
+
+ match self {
+ Wildcard => Constructor::split_wildcard(pcx),
+ // Fast-track if the range is trivial. In particular, we don't do the overlapping
+ // ranges check.
+ IntRange(ctor_range)
+ if ctor_range.treat_exhaustively(pcx.cx.tcx) && !ctor_range.is_singleton() =>
+ {
+ ctor_range.split(pcx, hir_id)
+ }
+ Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
+ // 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.
+ pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
+ // This must be kept in sync with `is_covered_by_any`.
+ match (self, other) {
+ // Wildcards cover anything
+ (_, Wildcard) => true,
+ // Wildcards are only covered by wildcards
+ (Wildcard, _) => false,
+
+ (Single, Single) => true,
+ (Variant(self_id), Variant(other_id)) => self_id == other_id,
+
+ (IntRange(self_range), IntRange(other_range)) => {
+ self_range.is_covered_by(pcx, other_range)
+ }
+ (
+ FloatRange(self_from, self_to, self_end),
+ FloatRange(other_from, other_to, other_end),
+ ) => {
+ match (
+ compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty),
+ compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty),
+ ) {
+ (Some(to), Some(from)) => {
+ (from == Ordering::Greater || from == Ordering::Equal)
+ && (to == Ordering::Less
+ || (other_end == self_end && to == Ordering::Equal))
+ }
+ _ => false,
+ }
+ }
+ (Str(self_val), Str(other_val)) => {
+ // FIXME: there's probably a more direct way of comparing for equality
+ match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty)
+ {
+ Some(comparison) => comparison == Ordering::Equal,
+ None => false,
+ }
+ }
+ (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
+
+ // We are trying to inspect an opaque constant. Thus we skip the row.
+ (Opaque, _) | (_, Opaque) => false,
+ // Only a wildcard pattern can match the special extra constructor.
+ (NonExhaustive, _) => false,
+
+ _ => span_bug!(
+ pcx.span,
+ "trying to compare incompatible constructors {:?} and {:?}",
+ self,
+ other
+ ),
+ }
+ }
+
+ /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
+ /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
+ /// assumed to have been split from a wildcard.
+ fn is_covered_by_any<'p>(
+ &self,
+ pcx: PatCtxt<'_, 'p, 'tcx>,
+ used_ctors: &[Constructor<'tcx>],
+ ) -> bool {
+ if used_ctors.is_empty() {
+ return false;
+ }
+
+ // This must be kept in sync with `is_covered_by`.
+ match self {
+ // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s.
+ Single => !used_ctors.is_empty(),
+ Variant(_) => used_ctors.iter().any(|c| c == self),
+ IntRange(range) => used_ctors
+ .iter()
+ .filter_map(|c| c.as_int_range())
+ .any(|other| range.is_covered_by(pcx, other)),
+ Slice(slice) => used_ctors
+ .iter()
+ .filter_map(|c| c.as_slice())
+ .any(|other| slice.is_covered_by(other)),
+ // This constructor is never covered by anything else
+ NonExhaustive => false,
+ Str(..) | FloatRange(..) | Opaque | Wildcard => {
+ bug!("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.
+///
+/// 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, pcx.span)
+ .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`.
+#[derive(Debug)]
+pub(super) struct MissingConstructors<'tcx> {
+ all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
+ used_ctors: Vec<Constructor<'tcx>>,
+}
+
+impl<'tcx> MissingConstructors<'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();
+
+ MissingConstructors { all_ctors, used_ctors }
+ }
+
+ fn is_empty<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> bool {
+ self.iter(pcx).next().is_none()
+ }
+
+ /// Iterate over all_ctors \ used_ctors
+ fn iter<'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))
+ }
+
+ /// 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()
+ }
+ }
+}
+
+/// 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.
+#[derive(Debug, Copy, Clone)]
+pub(super) enum FilteredField<'p, 'tcx> {
+ Kept(&'p Pat<'tcx>),
+ Hidden(Ty<'tcx>),
+}
+
+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),
+ }
+ }
+}
+
+/// 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`.
+///
+/// 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.
+#[derive(Debug, Clone)]
+pub(super) enum Fields<'p, 'tcx> {
+ /// Lists of patterns that don't contain any filtered fields.
+ /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and
+ /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril)
+ /// 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.
+ Filtered {
+ fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
+ kept_count: 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.
+ fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
+ Fields::Slice(std::slice::from_ref(pat))
+ }
+
+ /// Convenience; internal use.
+ fn wildcards_from_tys(
+ cx: &MatchCheckCtxt<'p, 'tcx>,
+ tys: impl IntoIterator<Item = Ty<'tcx>>,
+ ) -> Self {
+ let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
+ let pats = cx.pattern_arena.alloc_from_iter(wilds);
+ Fields::Slice(pats)
+ }
+
+ /// Creates a new list of wildcard fields for a given constructor.
+ pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
+ let ty = pcx.ty;
+ let cx = pcx.cx;
+ let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));
+
+ let ret = match constructor {
+ Single | Variant(_) => match ty.kind() {
+ ty::Tuple(ref fs) => {
+ Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty()))
+ }
+ ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)),
+ ty::Adt(adt, substs) => {
+ if adt.is_box() {
+ // Use T as the sub pattern type of Box<T>.
+ Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
+ } else {
+ let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
+ // Whether we must not match the fields of this variant exhaustively.
+ let is_non_exhaustive =
+ variant.is_field_list_non_exhaustive() && !adt.did.is_local();
+ let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs));
+ // In the following cases, we don't need to filter out any fields. This is
+ // the vast majority of real cases, since uninhabited fields are uncommon.
+ let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive)
+ || !field_tys.clone().any(|ty| cx.is_uninhabited(ty));
+
+ if has_no_hidden_fields {
+ Fields::wildcards_from_tys(cx, field_tys)
+ } else {
+ let mut kept_count = 0;
+ let fields = variant
+ .fields
+ .iter()
+ .map(|field| {
+ let ty = field.ty(cx.tcx, substs);
+ let is_visible = adt.is_enum()
+ || field.vis.is_accessible_from(cx.module, cx.tcx);
+ let is_uninhabited = cx.is_uninhabited(ty);
+
+ // In the cases of either a `#[non_exhaustive]` field list
+ // or a non-public field, we hide uninhabited fields in
+ // order not to reveal the uninhabitedness of the whole
+ // variant.
+ if is_uninhabited && (!is_visible || is_non_exhaustive) {
+ FilteredField::Hidden(ty)
+ } else {
+ kept_count += 1;
+ FilteredField::Kept(wildcard_from_ty(ty))
+ }
+ })
+ .collect();
+ Fields::Filtered { fields, kept_count }
+ }
+ }
+ }
+ _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
+ },
+ Slice(slice) => match *ty.kind() {
+ ty::Slice(ty) | ty::Array(ty, _) => {
+ let arity = slice.arity();
+ Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
+ }
+ _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
+ },
+ Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => {
+ Fields::empty()
+ }
+ };
+ debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
+ ret
+ }
+
+ /// Apply a constructor to a list of patterns, yielding a new pattern. `self`
+ /// must have as many elements as this constructor's arity.
+ ///
+ /// This is roughly the inverse of `specialize_constructor`.
+ ///
+ /// Examples:
+ /// `ctor`: `Constructor::Single`
+ /// `ty`: `Foo(u32, u32, u32)`
+ /// `self`: `[10, 20, _]`
+ /// returns `Foo(10, 20, _)`
+ ///
+ /// `ctor`: `Constructor::Variant(Option::Some)`
+ /// `ty`: `Option<bool>`
+ /// `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 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 })
+ .collect();
+
+ if let ty::Adt(adt, substs) = pcx.ty.kind() {
+ if adt.is_enum() {
+ PatKind::Variant {
+ adt_def: adt,
+ substs,
+ variant_index: ctor.variant_index_for_adt(adt),
+ subpatterns,
+ }
+ } else {
+ PatKind::Leaf { subpatterns }
+ }
+ } else {
+ PatKind::Leaf { subpatterns }
+ }
+ }
+ // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
+ // be careful to reconstruct the correct constant pattern here. However a string
+ // literal pattern will never be reported as a non-exhaustiveness witness, so we
+ // can ignore this issue.
+ ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
+ ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", ctor, pcx.ty),
+ _ => PatKind::Wild,
+ },
+ Slice(slice) => match slice.kind {
+ FixedLen(_) => {
+ PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
+ }
+ VarLen(prefix, _) => {
+ let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect();
+ if slice.array_len.is_some() {
+ // Improves diagnostics a bit: if the type is a known-size array, instead
+ // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
+ // This is incorrect if the size is not known, since `[_, ..]` captures
+ // arrays of lengths `>= 1` whereas `[..]` captures any length.
+ while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() {
+ prefix.pop();
+ }
+ }
+ let suffix: Vec<_> = if slice.array_len.is_some() {
+ // Same as above.
+ subpatterns.skip_while(Pat::is_wildcard).collect()
+ } else {
+ subpatterns.collect()
+ };
+ let wild = Pat::wildcard_from_ty(pcx.ty);
+ PatKind::Slice { prefix, slice: Some(wild), suffix }
+ }
+ },
+ &Str(value) => PatKind::Constant { value },
+ &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
+ IntRange(range) => return range.to_pat(pcx.cx.tcx),
+ NonExhaustive => PatKind::Wild,
+ 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`"
+ ),
+ };
+
+ 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`.
+ pub(super) fn len(&self) -> usize {
+ match self {
+ Fields::Slice(pats) => pats.len(),
+ Fields::Vec(pats) => pats.len(),
+ Fields::Filtered { kept_count, .. } => *kept_count,
+ }
+ }
+
+ /// 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(),
+ Fields::Filtered { fields, .. } => {
+ // We don't skip any fields here.
+ fields.into_iter().map(|p| p.to_pattern()).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]> {
+ 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()
+ }
+ }
+ }
+
+ /// Overrides some of the fields with the provided patterns. Exactly like
+ /// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
+ fn replace_with_fieldpats(
+ &self,
+ new_pats: impl IntoIterator<Item = &'p FieldPat<'tcx>>,
+ ) -> Self {
+ self.replace_fields_indexed(
+ new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)),
+ )
+ }
+
+ /// 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.
+ fn replace_fields_indexed(
+ &self,
+ new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
+ ) -> Self {
+ let mut fields = self.clone();
+ if let Fields::Slice(pats) = fields {
+ fields = Fields::Vec(pats.iter().collect());
+ }
+
+ match &mut fields {
+ Fields::Vec(pats) => {
+ for (i, pat) in new_pats {
+ pats[i] = pat
+ }
+ }
+ Fields::Filtered { fields, .. } => {
+ for (i, pat) in new_pats {
+ if let FilteredField::Kept(p) = &mut fields[i] {
+ *p = pat
+ }
+ }
+ }
+ Fields::Slice(_) => unreachable!(),
+ }
+ fields
+ }
+
+ /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the
+ /// matrix. There must be `len()` patterns in `pats`.
+ pub(super) fn replace_fields(
+ &self,
+ cx: &MatchCheckCtxt<'p, 'tcx>,
+ pats: impl IntoIterator<Item = Pat<'tcx>>,
+ ) -> Self {
+ let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
+
+ match self {
+ Fields::Filtered { fields, kept_count } => {
+ let mut pats = pats.iter();
+ let mut fields = fields.clone();
+ for f in &mut fields {
+ if let FilteredField::Kept(p) = f {
+ // We take one input pattern for each `Kept` field, in order.
+ *p = pats.next().unwrap();
+ }
+ }
+ Fields::Filtered { fields, kept_count: *kept_count }
+ }
+ _ => Fields::Slice(pats),
+ }
+ }
+
+ /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern
+ /// that is compatible with the constructor used to build `self`.
+ /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that
+ /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern
+ /// provided to this function fills some of the fields with non-wildcards.
+ /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call
+ /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _,
+ /// _, _]`.
+ /// ```rust
+ /// let x: [Option<u8>; 4] = foo();
+ /// match x {
+ /// [Some(0), ..] => {}
+ /// }
+ /// ```
+ /// This is guaranteed to preserve the number of patterns in `self`.
+ pub(super) fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self {
+ match pat.kind.as_ref() {
+ PatKind::Deref { subpattern } => {
+ assert_eq!(self.len(), 1);
+ Fields::from_single_pattern(subpattern)
+ }
+ PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
+ self.replace_with_fieldpats(subpatterns)
+ }
+ PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => {
+ // Number of subpatterns for the constructor
+ let ctor_arity = self.len();
+
+ // Replace the prefix and the suffix with the given patterns, leaving wildcards in
+ // the middle if there was a subslice pattern `..`.
+ let prefix = prefix.iter().enumerate();
+ let suffix =
+ suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p));
+ self.replace_fields_indexed(prefix.chain(suffix))
+ }
+ _ => self.clone(),
+ }
+ }
+}
//! Validation of patterns/matches.
-mod _match;
mod check_match;
mod const_to_pat;
+mod deconstruct_pat;
+mod usefulness;
pub(crate) use self::check_match::check_match;
--- /dev/null
+//! Note: tests specific to this file can be found in:
+//!
+//! - `ui/pattern/usefulness`
+//! - `ui/or-patterns`
+//! - `ui/consts/const_in_pattern`
+//! - `ui/rfc-2008-non-exhaustive`
+//! - `ui/half-open-range-patterns`
+//! - probably many others
+//!
+//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
+//! reason not to, for example if they depend on a particular feature like `or_patterns`.
+//!
+//! -----
+//!
+//! 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)
+//!
+//! 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).
+//!
+//! # 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).
+//!
+//! 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).
+//!
+//! # Core concept
+//!
+//! 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.
+//!
+//! 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.
+//!
+//! 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.
+//!
+//! 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.
+//!
+//! 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.
+//!
+//!
+//! # Algorithm
+//!
+//! 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`.
+//!
+//! For example, say we have the following:
+//!
+//! ```
+//! // x: (Option<bool>, Result<()>)
+//! match x {
+//! (Some(true), _) => {}
+//! (None, Err(())) => {}
+//! (None, Err(_)) => {}
+//! }
+//! ```
+//!
+//! Here, the matrix `P` starts as:
+//!
+//! ```
+//! [
+//! [(Some(true), _)],
+//! [(None, Err(()))],
+//! [(None, Err(_))],
+//! ]
+//! ```
+//!
+//! 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.
+//!
+//! 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.
+//!
+//! There are two important operations on pattern-stacks necessary to understand the algorithm:
+//!
+//! 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.
+//!
+//! 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.
+//!
+//! 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:
+//!
+//! 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`
+//!
+//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
+//! return nothing.
+//!
+//! 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`
+//!
+//! 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))`
+//!
+//! 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.
+//!
+//! 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))`
+//!
+//! 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.
+//!
+//! 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.
+//!
+//!
+//! 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.
+//!
+//! 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))`
+//!
+//! For example, if `P` is:
+//!
+//! ```
+//! [
+//! [Some(true), _],
+//! [None, 0],
+//! ]
+//! ```
+//!
+//! 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])`.
+//!
+//! - 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))`
+//!
+//! For example, if `P` is:
+//!
+//! ```
+//! [
+//! [_, true, _],
+//! [None, false, 1],
+//! ]
+//! ```
+//!
+//! 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])`.
+//!
+//! + 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 example, if `P` is:
+//!
+//! ```
+//! [
+//! [Some(true), _],
+//! [None, 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.
+//!
+//! - 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))`
+//!
+//! 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.
+//!
+//! 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).
+
+use self::Usefulness::*;
+use self::WitnessPreference::*;
+
+use super::deconstruct_pat::{Constructor, Fields, MissingConstructors};
+use super::{Pat, PatKind};
+use super::{PatternFoldable, PatternFolder};
+
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::OnceCell;
+
+use rustc_arena::TypedArena;
+use rustc_hir::def_id::DefId;
+use rustc_hir::HirId;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
+
+use smallvec::{smallvec, SmallVec};
+use std::fmt;
+use std::iter::{FromIterator, IntoIterator};
+
+crate struct MatchCheckCtxt<'a, 'tcx> {
+ crate tcx: TyCtxt<'tcx>,
+ /// The module in which the match occurs. This is necessary for
+ /// checking inhabited-ness of types because whether a type is (visibly)
+ /// inhabited can depend on whether it was defined in the current module or
+ /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
+ /// outside its module and should not be matchable with an empty match statement.
+ crate module: DefId,
+ crate param_env: ty::ParamEnv<'tcx>,
+ crate pattern_arena: &'a TypedArena<Pat<'tcx>>,
+}
+
+impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
+ pub(super) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
+ if self.tcx.features().exhaustive_patterns {
+ self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env)
+ } else {
+ false
+ }
+ }
+
+ /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
+ pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
+ match ty.kind() {
+ ty::Adt(def, ..) => {
+ def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
+ }
+ _ => false,
+ }
+ }
+}
+
+#[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.
+ pub(super) span: Span,
+ /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a
+ /// subpattern.
+ pub(super) is_top_level: bool,
+}
+
+crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
+ LiteralExpander.fold_pattern(&pat)
+}
+
+struct LiteralExpander;
+
+impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
+ fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
+ debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
+ match (pat.ty.kind(), pat.kind.as_ref()) {
+ (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self),
+ (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self),
+ (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => {
+ // Treat string literal patterns as deref patterns to a `str` constant, i.e.
+ // `&CONST`. This expands them like other const patterns. This could have been done
+ // in `const_to_pat`, but that causes issues with the rest of the matching code.
+ let mut new_pat = pat.super_fold_with(self);
+ // Make a fake const pattern of type `str` (instead of `&str`). That the carried
+ // constant value still knows it is of type `&str`.
+ new_pat.ty = t;
+ Pat {
+ kind: Box::new(PatKind::Deref { subpattern: new_pat }),
+ span: pat.span,
+ ty: pat.ty,
+ }
+ }
+ _ => pat.super_fold_with(self),
+ }
+ }
+}
+
+impl<'tcx> Pat<'tcx> {
+ pub(super) fn is_wildcard(&self) -> bool {
+ matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
+ }
+}
+
+/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
+/// works well.
+#[derive(Debug, Clone)]
+struct PatStack<'p, 'tcx> {
+ pats: SmallVec<[&'p Pat<'tcx>; 2]>,
+ /// Cache for the constructor of the head
+ head_ctor: OnceCell<Constructor<'tcx>>,
+}
+
+impl<'p, 'tcx> PatStack<'p, 'tcx> {
+ fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
+ Self::from_vec(smallvec![pat])
+ }
+
+ fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
+ PatStack { pats: vec, head_ctor: OnceCell::new() }
+ }
+
+ fn is_empty(&self) -> bool {
+ self.pats.is_empty()
+ }
+
+ fn len(&self) -> usize {
+ self.pats.len()
+ }
+
+ fn head(&self) -> &'p Pat<'tcx> {
+ self.pats[0]
+ }
+
+ fn head_ctor<'a>(&'a self, cx: &MatchCheckCtxt<'p, 'tcx>) -> &'a Constructor<'tcx> {
+ self.head_ctor.get_or_init(|| Constructor::from_pat(cx, self.head()))
+ }
+
+ fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
+ self.pats.iter().copied()
+ }
+
+ // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
+ fn expand_or_pat(&self) -> Option<Vec<Self>> {
+ if self.is_empty() {
+ None
+ } else if let PatKind::Or { pats } = &*self.head().kind {
+ Some(
+ pats.iter()
+ .map(|pat| {
+ let mut new_patstack = PatStack::from_pattern(pat);
+ new_patstack.pats.extend_from_slice(&self.pats[1..]);
+ new_patstack
+ })
+ .collect(),
+ )
+ } else {
+ None
+ }
+ }
+
+ /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
+ ///
+ /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
+ /// fields filled with wild patterns.
+ ///
+ /// This is roughly the inverse of `Constructor::apply`.
+ fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> {
+ // 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();
+ new_fields.extend_from_slice(&self.pats[1..]);
+ PatStack::from_vec(new_fields)
+ }
+}
+
+impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
+ fn default() -> Self {
+ Self::from_vec(smallvec![])
+ }
+}
+
+impl<'p, 'tcx> PartialEq for PatStack<'p, 'tcx> {
+ fn eq(&self, other: &Self) -> bool {
+ self.pats == other.pats
+ }
+}
+
+impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = &'p Pat<'tcx>>,
+ {
+ Self::from_vec(iter.into_iter().collect())
+ }
+}
+
+/// A 2D matrix.
+#[derive(Clone, PartialEq)]
+pub(super) struct Matrix<'p, 'tcx> {
+ patterns: Vec<PatStack<'p, 'tcx>>,
+}
+
+impl<'p, 'tcx> Matrix<'p, 'tcx> {
+ fn empty() -> Self {
+ Matrix { patterns: vec![] }
+ }
+
+ /// Number of columns of this matrix. `None` is the matrix is empty.
+ pub(super) fn column_count(&self) -> Option<usize> {
+ self.patterns.get(0).map(|r| r.len())
+ }
+
+ /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
+ fn push(&mut self, row: PatStack<'p, 'tcx>) {
+ if let Some(rows) = row.expand_or_pat() {
+ for row in rows {
+ // We recursively expand the or-patterns of the new rows.
+ // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`.
+ self.push(row)
+ }
+ } else {
+ self.patterns.push(row);
+ }
+ }
+
+ /// Iterate over the first component of each row
+ fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
+ self.patterns.iter().map(|r| r.head())
+ }
+
+ /// Iterate over the first constructor of each row
+ pub(super) fn head_ctors<'a>(
+ &'a self,
+ cx: &'a MatchCheckCtxt<'p, 'tcx>,
+ ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'a> + Captures<'p> {
+ self.patterns.iter().map(move |r| r.head_ctor(cx))
+ }
+
+ /// This computes `S(constructor, self)`. See top of the file for explanations.
+ fn specialize_constructor(
+ &self,
+ pcx: PatCtxt<'_, 'p, 'tcx>,
+ ctor: &Constructor<'tcx>,
+ ctor_wild_subpatterns: &Fields<'p, 'tcx>,
+ ) -> Matrix<'p, 'tcx> {
+ self.patterns
+ .iter()
+ .filter(|r| ctor.is_covered_by(pcx, r.head_ctor(pcx.cx)))
+ .map(|r| r.pop_head_constructor(ctor_wild_subpatterns))
+ .collect()
+ }
+}
+
+/// Pretty-printer for matrices of patterns, example:
+///
+/// ```text
+/// +++++++++++++++++++++++++++++
+/// + _ + [] +
+/// +++++++++++++++++++++++++++++
+/// + true + [First] +
+/// +++++++++++++++++++++++++++++
+/// + true + [Second(true)] +
+/// +++++++++++++++++++++++++++++
+/// + false + [_] +
+/// +++++++++++++++++++++++++++++
+/// + _ + [_, _, tail @ ..] +
+/// +++++++++++++++++++++++++++++
+/// ```
+impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "\n")?;
+
+ let Matrix { patterns: m, .. } = self;
+ let pretty_printed_matrix: Vec<Vec<String>> =
+ m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect();
+
+ let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
+ assert!(m.iter().all(|row| row.len() == column_count));
+ let column_widths: Vec<usize> = (0..column_count)
+ .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0))
+ .collect();
+
+ let total_width = column_widths.iter().cloned().sum::<usize>() + column_count * 3 + 1;
+ let br = "+".repeat(total_width);
+ write!(f, "{}\n", br)?;
+ for row in pretty_printed_matrix {
+ write!(f, "+")?;
+ for (column, pat_str) in row.into_iter().enumerate() {
+ write!(f, " ")?;
+ write!(f, "{:1$}", pat_str, column_widths[column])?;
+ write!(f, " +")?;
+ }
+ write!(f, "\n")?;
+ write!(f, "{}\n", br)?;
+ }
+ Ok(())
+ }
+}
+
+impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = PatStack<'p, 'tcx>>,
+ {
+ let mut matrix = Matrix::empty();
+ for x in iter {
+ // Using `push` ensures we correctly expand or-patterns.
+ matrix.push(x);
+ }
+ matrix
+ }
+}
+
+#[derive(Clone, Debug)]
+crate enum Usefulness<'tcx> {
+ /// Carries, for each column in the matrix, a set of sub-branches that have been found to be
+ /// unreachable. Used only in the presence of or-patterns, otherwise it stays empty.
+ Useful(Vec<FxHashSet<Span>>),
+ /// Carries a list of witnesses of non-exhaustiveness.
+ UsefulWithWitness(Vec<Witness<'tcx>>),
+ NotUseful,
+}
+
+impl<'tcx> Usefulness<'tcx> {
+ fn new_useful(preference: WitnessPreference) -> Self {
+ match preference {
+ ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
+ LeaveOutWitness => Useful(vec![]),
+ }
+ }
+
+ fn is_useful(&self) -> bool {
+ !matches!(*self, NotUseful)
+ }
+
+ fn apply_constructor<'p>(
+ self,
+ pcx: PatCtxt<'_, 'p, 'tcx>,
+ 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);
+ witnesses
+ .into_iter()
+ .flat_map(|witness| {
+ new_patterns.iter().map(move |pat| {
+ let mut witness = witness.clone();
+ witness.0.push(pat.clone());
+ witness
+ })
+ })
+ .collect()
+ } else {
+ witnesses
+ .into_iter()
+ .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
+ .collect()
+ };
+ UsefulWithWitness(new_witnesses)
+ }
+ Useful(mut unreachables) => {
+ if !unreachables.is_empty() {
+ // When we apply a constructor, there are `arity` columns of the matrix that
+ // corresponded to its arguments. All the unreachables found in these columns
+ // will, after `apply`, come from the first column. So we take the union of all
+ // the corresponding sets and put them in the first column.
+ // Note that `arity` may be 0, in which case we just push a new empty set.
+ let len = unreachables.len();
+ let arity = ctor_wild_subpatterns.len();
+ let mut unioned = FxHashSet::default();
+ for set in unreachables.drain((len - arity)..) {
+ unioned.extend(set)
+ }
+ unreachables.push(unioned);
+ }
+ Useful(unreachables)
+ }
+ x => x,
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+enum WitnessPreference {
+ ConstructWitness,
+ LeaveOutWitness,
+}
+
+/// A witness of non-exhaustiveness for error reporting, represented
+/// as a list of patterns (in reverse order of construction) with
+/// wildcards inside to represent elements that can take any inhabitant
+/// of the type as a value.
+///
+/// A witness against a list of patterns should have the same types
+/// and length as the pattern matched against. Because Rust `match`
+/// is always against a single pattern, at the end the witness will
+/// have length 1, but in the middle of the algorithm, it can contain
+/// multiple patterns.
+///
+/// For example, if we are constructing a witness for the match against
+///
+/// ```
+/// struct Pair(Option<(u32, u32)>, bool);
+///
+/// match (p: Pair) {
+/// Pair(None, _) => {}
+/// Pair(_, false) => {}
+/// }
+/// ```
+///
+/// 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])`
+/// 4. Apply the `Pair` constructor to the witnesses
+/// `Witness(vec![Pair(Some(_), true)])`
+///
+/// The final `Pair(Some(_), true)` is then the resulting witness.
+#[derive(Clone, Debug)]
+crate struct Witness<'tcx>(Vec<Pat<'tcx>>);
+
+impl<'tcx> Witness<'tcx> {
+ /// Asserts that the witness contains a single pattern, and returns it.
+ fn single_pattern(self) -> Pat<'tcx> {
+ assert_eq!(self.0.len(), 1);
+ self.0.into_iter().next().unwrap()
+ }
+
+ /// Constructs a partial witness for a pattern given a list of
+ /// patterns expanded by the specialization step.
+ ///
+ /// When a pattern P is discovered to be useful, this function is used bottom-up
+ /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset
+ /// of values, V, where each value in that set is not covered by any previously
+ /// used patterns and is covered by the pattern P'. Examples:
+ ///
+ /// left_ty: tuple of 3 elements
+ /// pats: [10, 20, _] => (10, 20, _)
+ ///
+ /// left_ty: struct X { a: (bool, &'static str), b: usize}
+ /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
+ fn apply_constructor<'p>(
+ mut self,
+ pcx: PatCtxt<'_, 'p, 'tcx>,
+ ctor: &Constructor<'tcx>,
+ ctor_wild_subpatterns: &Fields<'p, 'tcx>,
+ ) -> Self {
+ let pat = {
+ let len = self.0.len();
+ let arity = ctor_wild_subpatterns.len();
+ let pats = self.0.drain((len - arity)..).rev();
+ ctor_wild_subpatterns.replace_fields(pcx.cx, pats).apply(pcx, ctor)
+ };
+
+ self.0.push(pat);
+
+ self
+ }
+}
+
+/// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
+/// The algorithm from the paper has been modified to correctly handle empty
+/// types. The changes are:
+/// (0) We don't exit early if the pattern matrix has zero rows. We just
+/// continue to recurse over columns.
+/// (1) all_constructors will only return constructors that are statically
+/// possible. E.g., it will only return `Ok` for `Result<T, !>`.
+///
+/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
+/// to a set of such vectors `m` - this is defined as there being a set of
+/// inputs that will match `v` but not any of the sets in `m`.
+///
+/// All the patterns at each column of the `matrix ++ v` matrix must have the same type.
+///
+/// This is used both for reachability checking (if a pattern isn't useful in
+/// relation to preceding patterns, it is not reachable) and exhaustiveness
+/// checking (if a wildcard pattern is useful in relation to a matrix, the
+/// matrix isn't exhaustive).
+///
+/// `is_under_guard` is used to inform if the pattern has a guard. If it
+/// has one it must not be inserted into the matrix. This shouldn't be
+/// relied on for soundness.
+fn is_useful<'p, 'tcx>(
+ cx: &MatchCheckCtxt<'p, 'tcx>,
+ matrix: &Matrix<'p, 'tcx>,
+ v: &PatStack<'p, 'tcx>,
+ witness_preference: WitnessPreference,
+ hir_id: HirId,
+ is_under_guard: bool,
+ is_top_level: bool,
+) -> Usefulness<'tcx> {
+ let Matrix { patterns: rows, .. } = matrix;
+ debug!("is_useful({:#?}, {:#?})", matrix, v);
+
+ // The base case. We are pattern-matching on () and the return value is
+ // based on whether our matrix has a row or not.
+ // NOTE: This could potentially be optimized by checking rows.is_empty()
+ // first and then, if v is non-empty, the return value is based on whether
+ // the type of the tuple we're checking is inhabited or not.
+ if v.is_empty() {
+ return if rows.is_empty() {
+ Usefulness::new_useful(witness_preference)
+ } else {
+ NotUseful
+ };
+ };
+
+ assert!(rows.iter().all(|r| r.len() == v.len()));
+
+ // If the first pattern is an or-pattern, expand it.
+ if let Some(vs) = v.expand_or_pat() {
+ // We expand the or pattern, trying each of its branches in turn and keeping careful track
+ // of possible unreachable sub-branches.
+ //
+ // If two branches have detected some unreachable sub-branches, we need to be careful. If
+ // they were detected in columns that are not the current one, we want to keep only the
+ // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last
+ // `true` is unreachable in the second branch of the first or-pattern, but not otherwise.
+ // Therefore we don't want to lint that it is unreachable.
+ //
+ // ```
+ // match (true, true) {
+ // (true, true) => {}
+ // (false | true, false | true) => {}
+ // }
+ // ```
+ // If however the sub-branches come from the current column, they come from the inside of
+ // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want
+ // to lint that the last `false` is unreachable.
+ // ```
+ // match None {
+ // Some(false) => {}
+ // None | Some(true | false) => {}
+ // }
+ // ```
+
+ let mut matrix = matrix.clone();
+ // We keep track of sub-branches separately depending on whether they come from this column
+ // or from others.
+ let mut unreachables_this_column: FxHashSet<Span> = FxHashSet::default();
+ let mut unreachables_other_columns: Vec<FxHashSet<Span>> = Vec::default();
+ // Whether at least one branch is reachable.
+ let mut any_is_useful = false;
+
+ for v in vs {
+ let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ match res {
+ Useful(unreachables) => {
+ if let Some((this_column, other_columns)) = unreachables.split_last() {
+ // We keep the union of unreachables found in the first column.
+ unreachables_this_column.extend(this_column);
+ // We keep the intersection of unreachables found in other columns.
+ if unreachables_other_columns.is_empty() {
+ unreachables_other_columns = other_columns.to_vec();
+ } else {
+ unreachables_other_columns = unreachables_other_columns
+ .into_iter()
+ .zip(other_columns)
+ .map(|(x, y)| x.intersection(&y).copied().collect())
+ .collect();
+ }
+ }
+ any_is_useful = true;
+ }
+ NotUseful => {
+ unreachables_this_column.insert(v.head().span);
+ }
+ UsefulWithWitness(_) => bug!(
+ "encountered or-pat in the expansion of `_` during exhaustiveness checking"
+ ),
+ }
+
+ // If pattern has a guard don't add it to the matrix.
+ if !is_under_guard {
+ // We push the already-seen patterns into the matrix in order to detect redundant
+ // branches like `Some(_) | Some(0)`.
+ matrix.push(v);
+ }
+ }
+
+ return if any_is_useful {
+ let mut unreachables = if unreachables_other_columns.is_empty() {
+ let n_columns = v.len();
+ (0..n_columns - 1).map(|_| FxHashSet::default()).collect()
+ } else {
+ unreachables_other_columns
+ };
+ unreachables.push(unreachables_this_column);
+ Useful(unreachables)
+ } else {
+ NotUseful
+ };
+ }
+
+ // 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 };
+
+ debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
+
+ let ret = v
+ .head_ctor(cx)
+ .split(pcx, Some(hir_id))
+ .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 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)
+ })
+ .find(|result| result.is_useful())
+ .unwrap_or(NotUseful);
+ debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
+ ret
+}
+
+/// The arm of a match expression.
+#[derive(Clone, Copy)]
+crate struct MatchArm<'p, 'tcx> {
+ /// The pattern must have been lowered through `MatchVisitor::lower_pattern`.
+ crate pat: &'p super::Pat<'tcx>,
+ crate hir_id: HirId,
+ crate has_guard: bool,
+}
+
+/// The output of checking a match for exhaustiveness and arm reachability.
+crate struct UsefulnessReport<'p, 'tcx> {
+ /// For each arm of the input, whether that arm is reachable after the arms above it.
+ crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Usefulness<'tcx>)>,
+ /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
+ /// exhaustiveness.
+ crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>,
+}
+
+/// 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`.
+crate fn compute_match_usefulness<'p, 'tcx>(
+ cx: &MatchCheckCtxt<'p, 'tcx>,
+ arms: &[MatchArm<'p, 'tcx>],
+ scrut_hir_id: HirId,
+ scrut_ty: Ty<'tcx>,
+) -> UsefulnessReport<'p, 'tcx> {
+ let mut matrix = Matrix::empty();
+ let arm_usefulness: Vec<_> = arms
+ .iter()
+ .copied()
+ .map(|arm| {
+ let v = PatStack::from_pattern(arm.pat);
+ let usefulness =
+ is_useful(cx, &matrix, &v, LeaveOutWitness, arm.hir_id, arm.has_guard, true);
+ if !arm.has_guard {
+ matrix.push(v);
+ }
+ (arm, usefulness)
+ })
+ .collect();
+
+ let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty));
+ let v = PatStack::from_pattern(wild_pattern);
+ let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
+ let non_exhaustiveness_witnesses = match usefulness {
+ NotUseful => vec![], // Wildcard pattern isn't useful, so the match is exhaustive.
+ UsefulWithWitness(pats) => {
+ if pats.is_empty() {
+ bug!("Exhaustiveness check returned no witnesses")
+ } else {
+ pats.into_iter().map(|w| w.single_pattern()).collect()
+ }
+ }
+ Useful(_) => bug!(),
+ };
+ UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
+}
FatalError.raise()
}
- /// Note: It was decided to not add a test case, because it would be to big.
+ /// Note: It was decided to not add a test case, because it would be too big.
/// <https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180>
fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
self.fatal_span_(
//! The main parser interface.
-#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(bindings_after_at)]
#![feature(iter_order_by)]
#![feature(or_patterns)]
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_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 smallvec::SmallVec;
+use std::cell::RefCell;
use std::mem;
use std::path::Path;
use std::str;
// before we fall back to the stringification.
let convert_tokens =
- |tokens: &Option<LazyTokenStream>| tokens.as_ref().map(|t| t.create_token_stream());
+ |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::NtBlock(ref block) => convert_tokens(&block.tokens),
- Nonterminal::NtStmt(ref stmt) => {
- // FIXME: We currently only collect tokens for `:stmt`
- // matchers in `macro_rules!` macros. When we start collecting
- // tokens for attributes on statements, we will need to prepend
- // attributes here
- convert_tokens(&stmt.tokens)
- }
- Nonterminal::NtPat(ref pat) => convert_tokens(&pat.tokens),
- Nonterminal::NtTy(ref ty) => convert_tokens(&ty.tokens),
+ Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()),
+ Nonterminal::NtStmt(ref stmt) => prepend_attrs(stmt.attrs(), 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) => {
Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into())
}
Nonterminal::NtLifetime(ident) => {
Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into())
}
- Nonterminal::NtMeta(ref attr) => convert_tokens(&attr.tokens),
- Nonterminal::NtPath(ref path) => convert_tokens(&path.tokens),
- Nonterminal::NtVis(ref vis) => convert_tokens(&vis.tokens),
+ Nonterminal::NtMeta(ref attr) => convert_tokens(attr.tokens.as_ref()),
+ Nonterminal::NtPath(ref path) => convert_tokens(path.tokens.as_ref()),
+ Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.as_ref()),
Nonterminal::NtTT(ref tt) => Some(tt.clone().into()),
Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => {
if expr.tokens.is_none() {
}
};
+ // 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`).
// 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, sess, Some(span));
+ 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
// 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;
}
// 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,
true,
) {
+ GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
return tokens;
}
// 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 {
+ if let TokenTree::Token(token) = tree {
let mut out = SmallVec::<[_; 2]>::new();
- out.push(token.clone());
+ 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
use tracing::debug;
+// Public for rustfmt usage
#[derive(Debug)]
-pub(super) enum InnerAttrPolicy<'a> {
+pub enum InnerAttrPolicy<'a> {
Permitted,
Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}
/// Matches `attribute = # ! [ meta_item ]`.
/// `inner_parse_policy` prescribes how to handle inner attributes.
- fn parse_attribute(
+ // Public for rustfmt usage.
+ pub fn parse_attribute(
&mut self,
inner_parse_policy: InnerAttrPolicy<'_>,
) -> PResult<'a, ast::Attribute> {
}
pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
+ // One of the attributes may either itself be a macro, or apply derive macros (`derive`),
+ // or expand to macro attributes (`cfg_attr`).
attrs.iter().any(|attr| {
- if let Some(ident) = attr.ident() {
+ attr.ident().map_or(true, |ident| {
ident.name == sym::derive
- // This might apply a custom attribute/derive
- || ident.name == sym::cfg_attr
- || !rustc_feature::is_builtin_attr_name(ident.name)
- } else {
- true
- }
+ || ident.name == sym::cfg_attr
+ || !rustc_feature::is_builtin_attr_name(ident.name)
+ })
})
}
return Ok(false); // Don't continue.
}
- /// Handle a generic const argument that had not been enclosed in braces, and suggest enclosing
- /// it braces. In this situation, unlike in `handle_ambiguous_unbraced_const_arg`, this is
- /// almost certainly a const argument, so we always offer a suggestion.
+ /// Attempt to parse a generic const argument that has not been enclosed in braces.
+ /// There are a limited number of expressions that are permitted without being encoded
+ /// in braces:
+ /// - Literals.
+ /// - Single-segment paths (i.e. standalone generic const parameters).
+ /// All other expressions that can be parsed will emit an error suggesting the expression be
+ /// wrapped in braces.
pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> {
let start = self.token.span;
let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| {
//
// This also makes `Parser` very cheap to clone, since
// there is no intermediate collection buffer to clone.
+ #[derive(Clone)]
struct LazyTokenStreamImpl {
start_token: (Token, Spacing),
cursor_snapshot: TokenCursor,
num_calls: usize,
desugar_doc_comments: bool,
+ trailing_semi: bool,
}
impl CreateTokenStream for LazyTokenStreamImpl {
fn create_token_stream(&self) -> TokenStream {
+ let mut num_calls = self.num_calls;
+ if self.trailing_semi {
+ num_calls += 1;
+ }
// The token produced by the final call to `next` or `next_desugared`
// was not actually consumed by the callback. The combination
// of chaining the initial token and using `take` produces the desired
// and omit the final token otherwise.
let mut cursor_snapshot = self.cursor_snapshot.clone();
let tokens = std::iter::once(self.start_token.clone())
- .chain((0..self.num_calls).map(|_| {
+ .chain((0..num_calls).map(|_| {
if self.desugar_doc_comments {
cursor_snapshot.next_desugared()
} else {
cursor_snapshot.next()
}
}))
- .take(self.num_calls);
+ .take(num_calls);
make_token_stream(tokens)
}
+ fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> {
+ if self.trailing_semi {
+ panic!("Called `add_trailing_semi` twice!");
+ }
+ let mut new = self.clone();
+ new.trailing_semi = true;
+ Box::new(new)
+ }
}
let lazy_impl = LazyTokenStreamImpl {
num_calls: self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls,
cursor_snapshot,
desugar_doc_comments: self.desugar_doc_comments,
+ trailing_semi: false,
};
Ok((ret, Some(LazyTokenStream::new(lazy_impl))))
}
let (stmt, tokens) = self.collect_tokens(|this| this.parse_stmt())?;
match stmt {
Some(mut s) => {
- if s.tokens.is_none() {
- s.tokens = tokens;
+ if s.tokens().is_none() {
+ s.set_tokens(tokens);
}
token::NtStmt(s)
}
use crate::maybe_whole;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
-use rustc_ast::{
- self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs,
-};
+use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
+use rustc_ast::{GenericArg, GenericArgs};
use rustc_ast::{Path, PathSegment, QSelf};
use rustc_errors::{pluralize, Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
/// Parses a single argument in the angle arguments `<...>` of a path segment.
fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
- if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon))
- {
- // Parse associated type constraint.
- let lo = self.token.span;
- let ident = self.parse_ident()?;
- let kind = if self.eat(&token::Eq) {
- let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
- AssocTyConstraintKind::Equality { ty }
- } else if self.eat(&token::Colon) {
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
- AssocTyConstraintKind::Bound { bounds }
- } else {
- unreachable!();
- };
+ let lo = self.token.span;
+ let arg = self.parse_generic_arg()?;
+ match arg {
+ Some(arg) => {
+ if self.check(&token::Colon) | self.check(&token::Eq) {
+ let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
+ let kind = if self.eat(&token::Colon) {
+ // Parse associated type constraint bound.
+
+ let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ AssocTyConstraintKind::Bound { bounds }
+ } else if self.eat(&token::Eq) {
+ // Parse associated type equality constraint
+
+ let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
+ AssocTyConstraintKind::Equality { ty }
+ } else {
+ unreachable!();
+ };
- let span = lo.to(self.prev_token.span);
+ let span = lo.to(self.prev_token.span);
- // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
- if let AssocTyConstraintKind::Bound { .. } = kind {
- self.sess.gated_spans.gate(sym::associated_type_bounds, span);
+ // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
+ if let AssocTyConstraintKind::Bound { .. } = kind {
+ self.sess.gated_spans.gate(sym::associated_type_bounds, span);
+ }
+ let constraint =
+ AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
+ Ok(Some(AngleBracketedArg::Constraint(constraint)))
+ } else {
+ Ok(Some(AngleBracketedArg::Arg(arg)))
+ }
}
-
- let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span };
- Ok(Some(AngleBracketedArg::Constraint(constraint)))
- } else {
- Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg))
+ _ => Ok(None),
}
}
/// - An expression surrounded in `{}`.
/// - A literal.
/// - A numeric literal prefixed by `-`.
+ /// - A single-segment path.
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::Lit(_) => true,
_ => false,
},
+ // 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)
+ if path.segments.len() == 1 && path.segments[0].args.is_none() =>
+ {
+ true
+ }
_ => false,
}
}
};
Ok(Some(arg))
}
+
+ fn get_ident_from_generic_arg(
+ &self,
+ gen_arg: GenericArg,
+ lo: Span,
+ ) -> PResult<'a, (Ident, Option<GenericArgs>)> {
+ let gen_arg_span = gen_arg.span();
+ match gen_arg {
+ GenericArg::Type(t) => match t.into_inner().kind {
+ ast::TyKind::Path(qself, mut path) => {
+ if let Some(qself) = qself {
+ let mut err = self.struct_span_err(
+ gen_arg_span,
+ "qualified paths cannot be used in associated type constraints",
+ );
+ err.span_label(
+ qself.path_span,
+ "not allowed in associated type constraints",
+ );
+ return Err(err);
+ }
+ if path.segments.len() == 1 {
+ let path_seg = path.segments.remove(0);
+ let ident = path_seg.ident;
+ let gen_args = path_seg.args.map(|args| args.into_inner());
+ return Ok((ident, gen_args));
+ }
+ let err = self.struct_span_err(
+ path.span,
+ "paths with multiple segments cannot be used in associated type constraints",
+ );
+ return Err(err);
+ }
+ _ => {
+ let span = lo.to(self.prev_token.span);
+ let err = self.struct_span_err(
+ span,
+ "only path types can be used in associated type constraints",
+ );
+ return Err(err);
+ }
+ },
+ _ => {
+ let span = lo.to(self.prev_token.span);
+ let err = self
+ .struct_span_err(span, "only types can be used in associated type constraints");
+ return Err(err);
+ }
+ }
+ }
}
use crate::maybe_whole;
use rustc_ast as ast;
+use rustc_ast::attr::HasAttrs;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
+use rustc_ast::tokenstream::LazyTokenStream;
use rustc_ast::util::classify;
use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle};
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID};
}
fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
- maybe_whole!(self, NtStmt, |x| Some(x));
-
- let attrs = self.parse_outer_attributes()?;
+ let mut attrs = self.parse_outer_attributes()?;
+ let has_attrs = !attrs.is_empty();
let lo = self.token.span;
- let stmt = if self.eat_keyword(kw::Let) {
- self.parse_local_mk(lo, attrs.into())?
- } else if self.is_kw_followed_by_ident(kw::Mut) {
- self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
- } else if self.is_kw_followed_by_ident(kw::Auto) {
- self.bump(); // `auto`
- let msg = "write `let` instead of `auto` to introduce a new variable";
- self.recover_stmt_local(lo, attrs.into(), msg, "let")?
- } else if self.is_kw_followed_by_ident(sym::var) {
- self.bump(); // `var`
- let msg = "write `let` instead of `var` to introduce a new variable";
- self.recover_stmt_local(lo, attrs.into(), msg, "let")?
- } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
- // We have avoided contextual keywords like `union`, items with `crate` visibility,
- // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
- // that starts like a path (1 token), but it fact not a path.
- // Also, we avoid stealing syntax from `parse_item_`.
- self.parse_stmt_path_start(lo, attrs)?
- } else if let Some(item) = self.parse_item_common(attrs.clone(), false, true, |_| true)? {
- // FIXME: Bad copy of attrs
- self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
- } else if self.eat(&token::Semi) {
- // Do not attempt to parse an expression if we're done here.
- self.error_outer_attrs(&attrs);
- self.mk_stmt(lo, StmtKind::Empty)
- } else if self.token != token::CloseDelim(token::Brace) {
- // Remainder are line-expr stmts.
- let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
- self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
+ maybe_whole!(self, NtStmt, |stmt| {
+ let mut stmt = stmt;
+ stmt.visit_attrs(|stmt_attrs| {
+ mem::swap(stmt_attrs, &mut attrs);
+ stmt_attrs.extend(attrs);
+ });
+ Some(stmt)
+ });
+
+ let parse_stmt_inner = |this: &mut Self| {
+ let stmt = if this.eat_keyword(kw::Let) {
+ this.parse_local_mk(lo, attrs.into())?
+ } else if this.is_kw_followed_by_ident(kw::Mut) {
+ this.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
+ } else if this.is_kw_followed_by_ident(kw::Auto) {
+ this.bump(); // `auto`
+ let msg = "write `let` instead of `auto` to introduce a new variable";
+ this.recover_stmt_local(lo, attrs.into(), msg, "let")?
+ } else if this.is_kw_followed_by_ident(sym::var) {
+ this.bump(); // `var`
+ let msg = "write `let` instead of `var` to introduce a new variable";
+ this.recover_stmt_local(lo, attrs.into(), msg, "let")?
+ } else if this.check_path()
+ && !this.token.is_qpath_start()
+ && !this.is_path_start_item()
+ {
+ // We have avoided contextual keywords like `union`, items with `crate` visibility,
+ // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
+ // that starts like a path (1 token), but it fact not a path.
+ // Also, we avoid stealing syntax from `parse_item_`.
+ this.parse_stmt_path_start(lo, attrs)?
+ } else if let Some(item) =
+ this.parse_item_common(attrs.clone(), false, true, |_| true)?
+ {
+ // FIXME: Bad copy of attrs
+ this.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
+ } else if this.eat(&token::Semi) {
+ // Do not attempt to parse an expression if we're done here.
+ this.error_outer_attrs(&attrs);
+ this.mk_stmt(lo, StmtKind::Empty)
+ } else if this.token != token::CloseDelim(token::Brace) {
+ // Remainder are line-expr stmts.
+ let e = this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
+ this.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
+ } else {
+ this.error_outer_attrs(&attrs);
+ return Ok(None);
+ };
+ Ok(Some(stmt))
+ };
+
+ let stmt = if has_attrs {
+ let (mut stmt, tokens) = self.collect_tokens(parse_stmt_inner)?;
+ if let Some(stmt) = &mut stmt {
+ // If we already have tokens (e.g. due to encounting an `NtStmt`),
+ // use those instead.
+ if stmt.tokens().is_none() {
+ stmt.set_tokens(tokens);
+ }
+ }
+ stmt
} else {
- self.error_outer_attrs(&attrs);
- return Ok(None);
+ parse_stmt_inner(self)?
};
- Ok(Some(stmt))
+ Ok(stmt)
}
fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, Stmt> {
let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof
{
- StmtKind::MacCall(P(MacCallStmt { mac, style, attrs }))
+ StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
} else {
// Since none of the above applied, this is an expression statement macro.
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
}
};
let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span };
- Ok(P(ast::Local { ty, pat, init, id: DUMMY_NODE_ID, span: lo.to(hi), attrs }))
+ Ok(P(ast::Local { ty, pat, init, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None }))
}
/// Parses the RHS of a local variable declaration (e.g., '= 14;').
None => return Ok(None),
};
+ let add_semi_token = |tokens: Option<&mut LazyTokenStream>| {
+ if let Some(tokens) = tokens {
+ *tokens = tokens.add_trailing_semi();
+ }
+ };
+
let mut eat_semi = true;
match stmt.kind {
// Expression without semicolon.
*expr = self.mk_expr_err(sp);
}
}
+ StmtKind::Expr(_) | StmtKind::MacCall(_) => {}
StmtKind::Local(ref mut local) => {
if let Err(e) = self.expect_semi() {
// We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
}
}
eat_semi = false;
+ // We just checked that there's a semicolon in the tokenstream,
+ // so capture it
+ add_semi_token(local.tokens.as_mut());
}
- StmtKind::Empty => eat_semi = false,
- _ => {}
+ StmtKind::Empty | StmtKind::Item(_) | StmtKind::Semi(_) => eat_semi = false,
}
if eat_semi && self.eat(&token::Semi) {
stmt = stmt.add_trailing_semicolon();
+ // We just checked that we have a semicolon in the tokenstream,
+ // so capture it
+ add_semi_token(stmt.tokens_mut());
}
stmt.span = stmt.span.to(self.prev_token.span);
Ok(Some(stmt))
}
pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
- Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None }
+ Stmt { id: DUMMY_NODE_ID, kind, span }
}
pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt {
self.check_allow_internal_unstable(&attr, span, target, &attrs)
} else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) {
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
+ } else if self.tcx.sess.check_name(attr, sym::naked) {
+ self.check_naked(attr, span, target)
} else {
// lint-only checks
if self.tcx.sess.check_name(attr, sym::cold) {
}
}
+ /// Checks if `#[naked]` is applied to a function definition.
+ fn check_naked(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+ match target {
+ Target::Fn
+ | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+ _ => {
+ self.tcx
+ .sess
+ .struct_span_err(
+ attr.span,
+ "attribute should be applied to a function definition",
+ )
+ .span_label(*span, "not a function definition")
+ .emit();
+ false
+ }
+ }
+ }
+
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
fn check_track_caller(
&self,
target: Target,
) -> bool {
match target {
- _ if self.tcx.sess.contains_name(attrs, sym::naked) => {
+ _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
struct_span_err!(
self.tcx.sess,
*attr_span,
intravisit::walk_item(self, &item);
}
- hir::ItemKind::ForeignMod(..) => {}
+ hir::ItemKind::ForeignMod { .. } => {}
_ => {
intravisit::walk_item(self, &item);
}
fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) {
// ignore: we are handling this in `visit_item` above
}
+
+ fn visit_foreign_item(&mut self, _item: &'v hir::ForeignItem<'v>) {}
}
fn create_and_seed_worklist<'tcx>(
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
self.observe_item(&impl_item.attrs, impl_item.hir_id);
}
+
+ fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
+ self.observe_item(foreign_item.attrs, foreign_item.hir_id);
+ }
}
impl<'tcx> DiagnosticItemCollector<'tcx> {
// Collect diagnostic items in this crate.
tcx.hir().krate().visit_all_item_likes(&mut collector);
- // FIXME(visit_all_item_likes): Foreign items are not visited
- // here, so we have to manually look at them for now.
- for (_, foreign_module) in tcx.foreign_modules(LOCAL_CRATE).iter() {
- for &foreign_item in foreign_module.foreign_items.iter() {
- match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(foreign_item.expect_local())) {
- hir::Node::ForeignItem(item) => {
- collector.observe_item(item.attrs, item.hir_id);
- }
- item => bug!("unexpected foreign item {:?}", item),
- }
- }
+
+ for m in tcx.hir().krate().exported_macros {
+ collector.observe_item(m.attrs, m.hir_id);
}
collector.items
use rustc_errors::struct_span_err;
use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{HirId, ImplItem, Item, ItemKind, TraitItem};
+use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem<'tcx>) {
// Entry fn is never a trait item.
}
+
+ fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) {
+ // Entry fn is never a foreign item.
+ }
}
fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i));
}
+
+ fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
+ let mut inner_visitor = self.new_inner_visitor(self.hir_map);
+ inner_visitor.check(i.hir_id, |this| intravisit::walk_foreign_item(this, i));
+ }
}
impl<'a, 'hir> HirIdValidator<'a, 'hir> {
impl_item.attrs,
)
}
+
+ fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
}
impl LanguageItemCollector<'tcx> {
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
+ fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
}
impl LayoutTest<'tcx> {
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(const_fn)]
#![feature(const_panic)]
+#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(or_patterns)]
mod lib_features;
mod liveness;
pub mod loops;
+mod naked_functions;
mod reachable;
mod region;
pub mod stability;
lang_items::provide(providers);
lib_features::provide(providers);
loops::provide(providers);
+ naked_functions::provide(providers);
liveness::provide(providers);
intrinsicck::provide(providers);
reachable::provide(providers);
--- /dev/null
+use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+ tcx.hir().visit_item_likes_in_module(
+ module_def_id,
+ &mut CheckNakedFunctions { tcx }.as_deep_visitor(),
+ );
+}
+
+crate fn provide(providers: &mut Providers) {
+ *providers = Providers { check_mod_naked_functions, ..*providers };
+}
+
+struct CheckNakedFunctions<'tcx> {
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
+ type Map = ErasedMap<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_fn(
+ &mut self,
+ fk: FnKind<'v>,
+ _fd: &'tcx hir::FnDecl<'tcx>,
+ body_id: hir::BodyId,
+ _span: Span,
+ _hir_id: hir::HirId,
+ ) {
+ match fk {
+ // Rejected during attribute check. Do not validate further.
+ FnKind::Closure(..) => return,
+ FnKind::ItemFn(..) | FnKind::Method(..) => {}
+ }
+
+ let naked = fk.attrs().iter().any(|attr| attr.has_name(sym::naked));
+ if naked {
+ let body = self.tcx.hir().body(body_id);
+ check_params(self.tcx, body);
+ check_body(self.tcx, body);
+ }
+ }
+}
+
+/// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
+fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) {
+ for param in body.params {
+ match param.pat.kind {
+ hir::PatKind::Wild
+ | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {}
+ _ => {
+ tcx.sess
+ .struct_span_err(
+ param.pat.span,
+ "patterns not allowed in naked function parameters",
+ )
+ .emit();
+ }
+ }
+ }
+}
+
+/// Checks that function parameters aren't referenced in the function body.
+fn check_body<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
+ let mut params = hir::HirIdSet::default();
+ for param in body.params {
+ param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| {
+ params.insert(hir_id);
+ });
+ }
+ CheckBody { tcx, params }.visit_body(body);
+}
+
+struct CheckBody<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ params: hir::HirIdSet,
+}
+
+impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> {
+ type Map = ErasedMap<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::Path(hir::QPath::Resolved(
+ _,
+ hir::Path { res: hir::def::Res::Local(var_hir_id), .. },
+ )) = expr.kind
+ {
+ if self.params.contains(var_hir_id) {
+ self.tcx
+ .sess
+ .struct_span_err(
+ expr.span,
+ "use of parameters not allowed inside naked functions",
+ )
+ .emit();
+ }
+ }
+ hir::intravisit::walk_expr(self, expr);
+ }
+}
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Static(..)
| hir::ItemKind::Mod(..)
- | hir::ItemKind::ForeignMod(..)
+ | hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Impl { .. }
| hir::ItemKind::Trait(..)
| hir::ItemKind::TraitAlias(..)
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
// processed in visit_item above
}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {
+ // We never export foreign functions as they have no body to export.
+ }
}
fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> FxHashSet<LocalDefId> {
// they don't have their own stability. They still can be annotated as unstable
// and propagate this unstability to children, but this annotation is completely
// optional. They inherit stability from their parents when unannotated.
- hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) => {
+ hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. } => {
self.in_trait_impl = false;
kind = AnnotationKind::Container;
}
// optional. They inherit stability from their parents when unannotated.
if !matches!(
i.kind,
- hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..)
+ hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. }
) {
self.check_missing_stability(i.hir_id, i.span);
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
/// Finds the function marked with `#[plugin_registrar]`, if any.
Option::<AccessLevel>::of_impl(item.hir_id, self.tcx, &self.access_levels)
}
// Foreign modules inherit level from parents.
- hir::ItemKind::ForeignMod(..) => self.prev_level,
+ hir::ItemKind::ForeignMod { .. } => self.prev_level,
// Other `pub` items inherit levels from parents.
hir::ItemKind::Const(..)
| hir::ItemKind::Enum(..)
}
}
}
- hir::ItemKind::ForeignMod(ref foreign_mod) => {
- for foreign_item in foreign_mod.items {
+ hir::ItemKind::ForeignMod { items, .. } => {
+ for foreign_item in items {
if foreign_item.vis.node.is_pub() {
- self.update(foreign_item.hir_id, item_level);
+ self.update(foreign_item.id.hir_id, item_level);
}
}
}
hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::OpaqueTy(..) => {
// HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general)
- // Since rustdoc never need to do codegen and doesn't care about link-time reachability,
+ // Since rustdoc never needs to do codegen and doesn't care about link-time reachability,
// mark this as unreachable.
// See https://github.com/rust-lang/rust/issues/75100
if !self.tcx.sess.opts.actually_rustdoc {
}
}
// Visit everything, but foreign items have their own levels.
- hir::ItemKind::ForeignMod(ref foreign_mod) => {
- for foreign_item in foreign_mod.items {
- let foreign_item_level = self.get(foreign_item.hir_id);
+ hir::ItemKind::ForeignMod { items, .. } => {
+ for foreign_item in items {
+ let foreign_item_level = self.get(foreign_item.id.hir_id);
if foreign_item_level.is_some() {
- self.reach(foreign_item.hir_id, foreign_item_level)
+ self.reach(foreign_item.id.hir_id, foreign_item_level)
.generics()
.predicates()
.ty();
// An `extern {}` doesn't introduce a new privacy
// namespace (the contents have their own privacies).
- hir::ItemKind::ForeignMod(_) => {}
+ hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::Trait(.., ref bounds, _) => {
if !self.trait_is_public(item.hir_id) {
}
}
// Subitems of foreign modules have their own publicity.
- hir::ItemKind::ForeignMod(ref foreign_mod) => {
- for foreign_item in foreign_mod.items {
- let vis = tcx.visibility(tcx.hir().local_def_id(foreign_item.hir_id));
- self.check(foreign_item.hir_id, vis).generics().predicates().ty();
+ hir::ItemKind::ForeignMod { items, .. } => {
+ for foreign_item in items {
+ let vis = tcx.visibility(tcx.hir().local_def_id(foreign_item.id.hir_id));
+ self.check(foreign_item.id.hir_id, vis).generics().predicates().ty();
}
}
// Subitems of structs and unions have their own publicity.
use super::{DepContext, DepKind};
-use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
pub struct DepNode<K> {
pub kind: K,
- pub hash: Fingerprint,
+ pub hash: PackedFingerprint,
}
impl<K: DepKind> DepNode<K> {
/// does not require any parameters.
pub fn new_no_params(kind: K) -> DepNode<K> {
debug_assert!(!kind.has_params());
- DepNode { kind, hash: Fingerprint::ZERO }
+ DepNode { kind, hash: Fingerprint::ZERO.into() }
}
pub fn construct<Ctxt, Key>(tcx: Ctxt, kind: K, arg: &Key) -> DepNode<K>
Key: DepNodeParams<Ctxt>,
{
let hash = arg.to_fingerprint(tcx);
- let dep_node = DepNode { kind, hash };
+ let dep_node = DepNode { kind, hash: hash.into() };
#[cfg(debug_assertions)]
{
// 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()),
+ hash: self.anon_id_seed.combine(hasher.finish()).into(),
};
self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO)
pub(crate) type QueryMap<D, Q> = FxHashMap<QueryJobId<D>, QueryJobInfo<D, Q>>;
-/// A value uniquely identifiying an active query job within a shard in the query cache.
+/// A value uniquely identifying an active query job within a shard in the query cache.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct QueryShardJobId(pub NonZeroU32);
-/// A value uniquely identifiying an active query job.
+/// A value uniquely identifying an active query job.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct QueryJobId<D> {
/// Which job within a shard is this
};
// We unwrap `waiter` here since there must always be one
- // edge which is resumeable / waited using a query latch
+ // edge which is resumable / waited using a query latch
let (waitee_query, waiter_idx) = waiter.unwrap();
// Extract the waiter we want to resume
false
}
- fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> {
+ fn visit_invoc(&mut self, id: NodeId) -> ExpnId {
let invoc_id = id.placeholder_to_expn_id();
-
- self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
-
let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");
+ invoc_id
+ }
+ /// Visit invocation in context in which it can emit a named item (possibly `macro_rules`)
+ /// directly into its parent scope's module.
+ fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> {
+ let invoc_id = self.visit_invoc(id);
+ self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
}
return;
}
ItemKind::MacCall(..) => {
- self.parent_scope.macro_rules = self.visit_invoc(item.id);
+ self.parent_scope.macro_rules = self.visit_invoc_in_module(item.id);
return;
}
ItemKind::Mod(..) => self.contains_macro_use(&item.attrs),
fn visit_stmt(&mut self, stmt: &'b ast::Stmt) {
if let ast::StmtKind::MacCall(..) = stmt.kind {
- self.parent_scope.macro_rules = self.visit_invoc(stmt.id);
+ self.parent_scope.macro_rules = self.visit_invoc_in_module(stmt.id);
} else {
visit::walk_stmt(self, stmt);
}
fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) {
if let ForeignItemKind::MacCall(_) = foreign_item.kind {
- self.visit_invoc(foreign_item.id);
+ self.visit_invoc_in_module(foreign_item.id);
return;
}
fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
if let AssocItemKind::MacCall(_) = item.kind {
- self.visit_invoc(item.id);
+ match ctxt {
+ AssocCtxt::Trait => {
+ self.visit_invoc_in_module(item.id);
+ }
+ AssocCtxt::Impl => {
+ self.visit_invoc(item.id);
+ }
+ }
return;
}
// type and value namespaces.
fn visit_variant(&mut self, variant: &'b ast::Variant) {
if variant.is_placeholder {
- self.visit_invoc(variant.id);
+ self.visit_invoc_in_module(variant.id);
return;
}
use std::cmp::Reverse;
use std::ptr;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_ast::{self as ast, Path};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::{self, DefIdTree};
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span};
_ => {
bug!(
"GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
- DefKind::TyParam"
+ DefKind::TyParam or DefKind::ConstParam"
);
}
}
name
));
}
+ err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions");
err
}
}
}
Scope::DeriveHelpersCompat => {
- let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+ let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
if filter_fn(res) {
for derive in parent_scope.derives {
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
match find_best_match_for_name(
- suggestions.iter().map(|suggestion| &suggestion.candidate),
+ &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
ident.name,
None,
) {
use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};
use rustc_ast::unwrap_or;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_ast::NodeId;
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::DiagnosticMessageId;
use rustc_span::hygiene::ExpnId;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{MultiSpan, Span};
_ => None,
};
let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
- let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
- if *i == ident {
- return None;
- } // Never suggest the same name
- match *resolution.borrow() {
- NameResolution { binding: Some(name_binding), .. } => {
- match name_binding.kind {
- NameBindingKind::Import { binding, .. } => {
- match binding.kind {
- // Never suggest the name that has binding error
- // i.e., the name that cannot be previously resolved
- NameBindingKind::Res(Res::Err, _) => None,
- _ => Some(&i.name),
+ let names = resolutions
+ .filter_map(|(BindingKey { ident: i, .. }, resolution)| {
+ if *i == ident {
+ return None;
+ } // Never suggest the same name
+ match *resolution.borrow() {
+ NameResolution { binding: Some(name_binding), .. } => {
+ match name_binding.kind {
+ NameBindingKind::Import { binding, .. } => {
+ match binding.kind {
+ // Never suggest the name that has binding error
+ // i.e., the name that cannot be previously resolved
+ NameBindingKind::Res(Res::Err, _) => None,
+ _ => Some(i.name),
+ }
}
+ _ => Some(i.name),
}
- _ => Some(&i.name),
}
+ NameResolution { ref single_imports, .. }
+ if single_imports.is_empty() =>
+ {
+ None
+ }
+ _ => Some(i.name),
}
- NameResolution { ref single_imports, .. } if single_imports.is_empty() => {
- None
- }
- _ => Some(&i.name),
- }
- });
+ })
+ .collect::<Vec<Symbol>>();
let lev_suggestion =
- find_best_match_for_name(names, ident.name, None).map(|suggestion| {
+ find_best_match_for_name(&names, ident.name, None).map(|suggestion| {
(
vec![(ident.span, suggestion.to_string())],
String::from("a similar name exists in the module"),
use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_ast::visit::FnKind;
use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
use rustc_ast_pretty::pprust::path_segment_to_string;
use rustc_hir::PrimTy;
use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
match find_best_match_for_name(
- names.iter().map(|suggestion| &suggestion.candidate),
+ &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
name,
None,
) {
.bindings
.iter()
.filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
- .map(|(id, _)| &id.name);
+ .map(|(id, _)| id.name)
+ .collect::<Vec<Symbol>>();
- find_best_match_for_name(names, label.name, None).map(|symbol| {
+ find_best_match_for_name(&names, label.name, None).map(|symbol| {
// Upon finding a similar name, get the ident that it was from - the span
// contained within helps make a useful diagnostic. In addition, determine
// whether this candidate is within scope.
hir::ItemKind::ExternCrate(_)
| hir::ItemKind::Use(..)
| hir::ItemKind::Mod(..)
- | hir::ItemKind::ForeignMod(..)
+ | hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::GlobalAsm(..) => {
// These sorts of items have no lifetime parameters at all.
intravisit::walk_item(self, item);
span: Span,
all_ribs: &[Rib<'a>],
) -> Res {
+ const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation";
debug!("validate_res_from_ribs({:?})", res);
let ribs = &all_ribs[rib_index + 1..];
},
);
}
+
+ self.session.delay_span_bug(span, CG_BUG_STR);
return Res::Err;
}
}
},
);
}
+
+ self.session.delay_span_bug(span, CG_BUG_STR);
return Res::Err;
}
use rustc_attr::StabilityLevel;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
use rustc_expand::compile_declarative_macro;
-use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
+use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
use rustc_feature::is_builtin_attr_name;
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
use rustc_hir::def_id;
use rustc_middle::middle::stability;
use rustc_middle::ty;
-use rustc_session::lint::builtin::UNUSED_MACROS;
+use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
+use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind};
+use rustc_span::hygiene::{AstPass, MacroKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
-
-use rustc_data_structures::sync::Lrc;
-use rustc_span::hygiene::{AstPass, MacroKind};
use std::cell::Cell;
use std::{mem, ptr};
}
};
- let (path, kind, derives, after_derive) = match invoc.kind {
+ let (path, kind, inner_attr, derives, after_derive) = match invoc.kind {
InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (
&attr.get_normal_item().path,
MacroKind::Attr,
+ attr.style == ast::AttrStyle::Inner,
self.arenas.alloc_ast_paths(derives),
after_derive,
),
- InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false),
- InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false),
+ InvocationKind::Bang { ref mac, .. } => {
+ (&mac.path, MacroKind::Bang, false, &[][..], false)
+ }
+ InvocationKind::Derive { ref path, .. } => {
+ (path, MacroKind::Derive, false, &[][..], false)
+ }
InvocationKind::DeriveContainer { ref derives, .. } => {
// Block expansion of the container until we resolve all derives in it.
// This is required for two reasons:
ext.helper_attrs.iter().map(|name| Ident::new(*name, span)),
);
if ext.is_derive_copy {
- self.add_derive_copy(invoc_id);
+ self.containers_deriving_copy.insert(invoc_id);
}
ext
}
// Derives are not included when `invocations` are collected, so we have to add them here.
let parent_scope = &ParentScope { derives, ..parent_scope };
+ let require_inert = !invoc.fragment_kind.supports_macro_expansion();
let node_id = self.lint_node_id(eager_expansion_root);
- let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, node_id, force)?;
+ let (ext, res) = self.smart_resolve_macro_path(
+ path,
+ kind,
+ require_inert,
+ inner_attr,
+ parent_scope,
+ node_id,
+ force,
+ )?;
let span = invoc.span();
invoc_id.set_expn_data(ext.expn_data(
self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
}
- match invoc.fragment_kind {
- AstFragmentKind::Arms
- | AstFragmentKind::Fields
- | AstFragmentKind::FieldPats
- | AstFragmentKind::GenericParams
- | AstFragmentKind::Params
- | AstFragmentKind::StructFields
- | AstFragmentKind::Variants => {
- if let Res::Def(..) = res {
- self.session.span_err(
- span,
- &format!(
- "expected an inert attribute, found {} {}",
- res.article(),
- res.descr()
- ),
- );
- return Ok(InvocationRes::Single(self.dummy_ext(kind)));
- }
- }
- _ => {}
- }
-
Ok(InvocationRes::Single(ext))
}
self.containers_deriving_copy.contains(&expn_id)
}
- fn add_derive_copy(&mut self, expn_id: ExpnId) {
- self.containers_deriving_copy.insert(expn_id);
- }
-
// The function that implements the resolution logic of `#[cfg_accessible(path)]`.
// Returns true if the path can certainly be resolved in one of three namespaces,
// returns false if the path certainly cannot be resolved in any of the three namespaces.
impl<'a> Resolver<'a> {
/// Resolve macro path with error reporting and recovery.
+ /// Uses dummy syntax extensions for unresolved macros or macros with unexpected resolutions
+ /// for better error recovery.
fn smart_resolve_macro_path(
&mut self,
path: &ast::Path,
kind: MacroKind,
+ require_inert: bool,
+ inner_attr: bool,
parent_scope: &ParentScope<'a>,
node_id: NodeId,
force: bool,
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
{
Ok((Some(ext), res)) => (ext, res),
- // Use dummy syntax extensions for unresolved macros for better recovery.
Ok((None, res)) => (self.dummy_ext(kind), res),
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
Err(Determinacy::Undetermined) => return Err(Indeterminate),
self.check_stability_and_deprecation(&ext, path, node_id);
- Ok(if ext.macro_kind() != kind {
- let expected = kind.descr_expected();
+ let unexpected_res = if ext.macro_kind() != kind {
+ Some((kind.article(), kind.descr_expected()))
+ } else if require_inert && matches!(res, Res::Def(..)) {
+ Some(("a", "non-macro attribute"))
+ } else {
+ None
+ };
+ if let Some((article, expected)) = unexpected_res {
let path_str = pprust::path_to_string(path);
let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str);
self.session
.struct_span_err(path.span, &msg)
- .span_label(path.span, format!("not {} {}", kind.article(), expected))
+ .span_label(path.span, format!("not {} {}", article, expected))
.emit();
- // Use dummy syntax extensions for unexpected macro kinds for better recovery.
- (self.dummy_ext(kind), Res::Err)
- } else {
- (ext, res)
- })
+ return Ok((self.dummy_ext(kind), Res::Err));
+ }
+
+ // We are trying to avoid reporting this error if other related errors were reported.
+ if res != Res::Err
+ && inner_attr
+ && !self.session.features_untracked().custom_inner_attributes
+ {
+ let msg = match res {
+ Res::Def(..) => "inner macro attributes are unstable",
+ Res::NonMacroAttr(..) => "custom inner attributes are unstable",
+ _ => unreachable!(),
+ };
+ if path == &sym::test {
+ self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
+ } else {
+ feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg)
+ .emit();
+ }
+ }
+
+ Ok((ext, res))
}
pub fn resolve_macro_path(
struct Flags: u8 {
const MACRO_RULES = 1 << 0;
const MODULE = 1 << 1;
- const DERIVE_HELPER_COMPAT = 1 << 2;
- const MISC_SUGGEST_CRATE = 1 << 3;
- const MISC_SUGGEST_SELF = 1 << 4;
- const MISC_FROM_PRELUDE = 1 << 5;
+ const MISC_SUGGEST_CRATE = 1 << 2;
+ const MISC_SUGGEST_SELF = 1 << 3;
+ const MISC_FROM_PRELUDE = 1 << 4;
}
}
) {
Ok((Some(ext), _)) => {
if ext.helper_attrs.contains(&ident.name) {
- let binding = (
- Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
- ty::Visibility::Public,
+ result = ok(
+ Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat),
derive.span,
- ExpnId::root(),
- )
- .to_name_binding(this.arenas);
- result = Ok((binding, Flags::DERIVE_HELPER_COMPAT));
+ this.arenas,
+ );
break;
}
}
let (res, innermost_res) = (binding.res(), innermost_binding.res());
if res != innermost_res {
let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
- let is_derive_helper_compat = |res, flags: Flags| {
- res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper)
- && flags.contains(Flags::DERIVE_HELPER_COMPAT)
- };
+ let derive_helper_compat =
+ Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
let ambiguity_error_kind = if is_import {
Some(AmbiguityKind::Import)
} else if innermost_res == builtin || res == builtin {
Some(AmbiguityKind::BuiltinAttr)
- } else if is_derive_helper_compat(innermost_res, innermost_flags)
- || is_derive_helper_compat(res, flags)
+ } else if innermost_res == derive_helper_compat
+ || res == derive_helper_compat
{
Some(AmbiguityKind::DeriveHelper)
} else if innermost_flags.contains(Flags::MACRO_RULES)
// FIXME where clause
}
- hir::ItemKind::ForeignMod(_) => Err("extern mod"),
+ hir::ItemKind::ForeignMod { .. } => Err("extern mod"),
hir::ItemKind::GlobalAsm(_) => Err("global asm"),
hir::ItemKind::ExternCrate(_) => Err("extern crate"),
hir::ItemKind::OpaqueTy(..) => Err("opaque type"),
"emits a future-incompatibility report for lints (RFC 2834)"),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emit a section containing stack size metadata (default: no)"),
- fewer_names: bool = (false, parse_bool, [TRACKED],
+ fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
(default: no)"),
force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
"whether to use the PLT when calling into shared libraries;
only has effect for PIC code on systems with ELF binaries
(default: PLT is disabled if full relro is enabled)"),
- polonius: bool = (false, parse_bool, [UNTRACKED],
+ polonius: bool = (false, parse_bool, [TRACKED],
"enable polonius-based borrow-checker (default: no)"),
polymorphize: bool = (false, parse_bool, [TRACKED],
"perform polymorphization analysis"),
"choose the TLS model to use (`rustc --print tls-models` for details)"),
trace_macros: bool = (false, parse_bool, [UNTRACKED],
"for every macro invocation, print its name and arguments (default: no)"),
+ trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
"treat error number `val` that occurs as bug"),
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
self.opts.cg.panic.unwrap_or(self.target.panic_strategy)
}
pub fn fewer_names(&self) -> bool {
- let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
- || self.opts.output_types.contains_key(&OutputType::Bitcode)
- // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
- || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
-
- self.opts.debugging_opts.fewer_names || !more_names
+ if let Some(fewer_names) = self.opts.debugging_opts.fewer_names {
+ fewer_names
+ } else {
+ let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
+ || self.opts.output_types.contains_key(&OutputType::Bitcode)
+ // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
+ || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
+ !more_names
+ }
}
pub fn unstable_options(&self) -> bool {
--- /dev/null
+use crate::symbol::Symbol;
+use std::cmp;
+
+#[cfg(test)]
+mod tests;
+
+/// 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() {
+ return b.chars().count();
+ } else if b.is_empty() {
+ return a.chars().count();
+ }
+
+ let mut dcol: Vec<_> = (0..=b.len()).collect();
+ let mut t_last = 0;
+
+ for (i, sc) in a.chars().enumerate() {
+ let mut current = i;
+ dcol[0] = current + 1;
+
+ for (j, tc) in b.chars().enumerate() {
+ let next = dcol[j + 1];
+ if sc == tc {
+ dcol[j + 1] = current;
+ } else {
+ dcol[j + 1] = cmp::min(current, next);
+ dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
+ }
+ current = next;
+ t_last = j;
+ }
+ }
+ dcol[t_last + 1]
+}
+
+/// 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.
+#[cold]
+pub fn find_best_match_for_name(
+ name_vec: &[Symbol],
+ lookup: Symbol,
+ dist: Option<usize>,
+) -> Option<Symbol> {
+ let lookup = &lookup.as_str();
+ let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
+
+ let (case_insensitive_match, levenshtein_match) = name_vec
+ .iter()
+ .filter_map(|&name| {
+ let dist = lev_distance(lookup, &name.as_str());
+ if dist <= max_dist { Some((name, dist)) } else { None }
+ })
+ // Here we are collecting the next structure:
+ // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
+ .fold((None, None), |result, (candidate, dist)| {
+ (
+ if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
+ Some(candidate)
+ } else {
+ result.0
+ },
+ match result.1 {
+ None => Some((candidate, dist)),
+ Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
+ },
+ )
+ });
+ // Priority of matches:
+ // 1. Exact case insensitive match
+ // 2. Levenshtein distance match
+ // 3. Sorted word match
+ if let Some(candidate) = case_insensitive_match {
+ Some(candidate)
+ } else if levenshtein_match.is_some() {
+ levenshtein_match.map(|(candidate, _)| candidate)
+ } else {
+ find_match_by_sorted_words(name_vec, lookup)
+ }
+}
+
+fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option<Symbol> {
+ iter_names.iter().fold(None, |result, candidate| {
+ if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) {
+ Some(*candidate)
+ } else {
+ result
+ }
+ })
+}
+
+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
+ split_words.sort_unstable();
+ split_words.join("_")
+}
--- /dev/null
+use super::*;
+
+#[test]
+fn test_lev_distance() {
+ use std::char::{from_u32, MAX};
+ // Test bytelength agnosticity
+ for c in (0..MAX as u32).filter_map(|i| from_u32(i)).map(|i| i.to_string()) {
+ assert_eq!(lev_distance(&c[..], &c[..]), 0);
+ }
+
+ let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
+ let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
+ let c = "Mary häd ä little lämb\n\nLittle lämb\n";
+ assert_eq!(lev_distance(a, b), 1);
+ assert_eq!(lev_distance(b, a), 1);
+ assert_eq!(lev_distance(a, c), 2);
+ assert_eq!(lev_distance(c, a), 2);
+ assert_eq!(lev_distance(b, c), 1);
+ assert_eq!(lev_distance(c, b), 1);
+}
+
+#[test]
+fn test_find_best_match_for_name() {
+ use crate::with_default_session_globals;
+ with_default_session_globals(|| {
+ let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")];
+ assert_eq!(
+ find_best_match_for_name(&input, Symbol::intern("aaaa"), None),
+ Some(Symbol::intern("aaab"))
+ );
+
+ assert_eq!(find_best_match_for_name(&input, Symbol::intern("1111111111"), None), None);
+
+ let input = vec![Symbol::intern("aAAA")];
+ assert_eq!(
+ find_best_match_for_name(&input, Symbol::intern("AAAA"), None),
+ Some(Symbol::intern("aAAA"))
+ );
+
+ let input = vec![Symbol::intern("AAAA")];
+ // Returns None because `lev_distance > max_dist / 3`
+ assert_eq!(find_best_match_for_name(&input, Symbol::intern("aaaa"), None), None);
+
+ let input = vec![Symbol::intern("AAAA")];
+ assert_eq!(
+ find_best_match_for_name(&input, Symbol::intern("aaaa"), Some(4)),
+ Some(Symbol::intern("AAAA"))
+ );
+
+ let input = vec![Symbol::intern("a_longer_variable_name")];
+ assert_eq!(
+ find_best_match_for_name(&input, Symbol::intern("a_variable_longer_name"), None),
+ Some(Symbol::intern("a_longer_variable_name"))
+ );
+ })
+}
pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
pub mod def_id;
use def_id::{CrateNum, DefId, LOCAL_CRATE};
+pub mod lev_distance;
mod span_encoding;
pub use span_encoding::{Span, DUMMY_SP};
asm,
assert,
assert_inhabited,
+ assert_macro,
assert_receiver_is_total_eq,
assert_uninit_valid,
assert_zero_valid,
attr_literals,
attributes,
augmented_assignments,
+ auto_traits,
automatically_derived,
avx512_target_feature,
await_macro,
copysignf64,
core,
core_intrinsics,
+ core_panic_macro,
cosf32,
cosf64,
crate_id,
dead_code,
dealloc,
debug,
+ debug_assert_macro,
debug_assertions,
debug_struct,
debug_trait,
panic_runtime,
panic_str,
panic_unwind,
+ panicking,
param_attrs,
parent_trait,
partial_cmp,
staticlib,
std,
std_inject,
+ std_panic_macro,
stmt,
stmt_expr_attributes,
stop_after_dataflow,
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
self.process_attrs(impl_item.hir_id);
}
+
+ fn visit_foreign_item(&mut self, foreign_item: &'tcx hir::ForeignItem<'tcx>) {
+ self.process_attrs(foreign_item.hir_id);
+ }
}
-use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
use crate::abi::{self, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods};
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
if let abi::Int(i, signed) = scalar.value {
if !signed && i.size().bits() == 32 {
if let PassMode::Direct(ref mut attrs) = arg.mode {
- attrs.set(ArgAttribute::SExt);
+ attrs.ext(ArgExtension::Sext);
return;
}
}
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
arg.cast_to(CastTarget {
prefix,
- prefix_chunk: Size::from_bytes(8),
+ prefix_chunk_size: Size::from_bytes(8),
rest: Uniform { unit: Reg::i64(), total: rest_size },
});
}
/// a single uniform or a pair of registers.
Cast(CastTarget),
/// Pass the argument indirectly via a hidden pointer.
- /// The second value, if any, is for the extra data (vtable or length)
+ /// The `extra_attrs` value, if any, is for the extra data (vtable or length)
/// which indicates that it refers to an unsized rvalue.
- Indirect(ArgAttributes, Option<ArgAttributes>),
+ /// `on_stack` defines that the the value should be passed at a fixed
+ /// stack offset in accordance to the ABI rather than passed using a
+ /// pointer. This corresponds to the `byval` LLVM argument attribute.
+ Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool },
}
// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
bitflags::bitflags! {
#[derive(Default)]
pub struct ArgAttribute: u16 {
- const ByVal = 1 << 0;
const NoAlias = 1 << 1;
const NoCapture = 1 << 2;
const NonNull = 1 << 3;
const ReadOnly = 1 << 4;
- const SExt = 1 << 5;
- const StructRet = 1 << 6;
- const ZExt = 1 << 7;
const InReg = 1 << 8;
}
}
}
+/// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum
+/// defines if this extension should be zero-extension or sign-extension when necssary. When it is
+/// not necesary to extend the argument, this enum is ignored.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum ArgExtension {
+ None,
+ Zext,
+ Sext,
+}
+
/// A compact representation of LLVM attributes (at least those relevant for this module)
/// that can be manipulated without interacting with LLVM's Attribute machinery.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ArgAttributes {
pub regular: ArgAttribute,
+ pub arg_ext: ArgExtension,
/// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
/// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
pub pointee_size: Size,
pub fn new() -> Self {
ArgAttributes {
regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
pointee_size: Size::ZERO,
pointee_align: None,
}
}
+ pub fn ext(&mut self, ext: ArgExtension) -> &mut Self {
+ assert!(self.arg_ext == ArgExtension::None || self.arg_ext == ext);
+ self.arg_ext = ext;
+ self
+ }
+
pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
self.regular |= attr;
self
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct CastTarget {
pub prefix: [Option<RegKind>; 8],
- pub prefix_chunk: Size,
+ pub prefix_chunk_size: Size,
pub rest: Uniform,
}
impl From<Uniform> for CastTarget {
fn from(uniform: Uniform) -> CastTarget {
- CastTarget { prefix: [None; 8], prefix_chunk: Size::ZERO, rest: uniform }
+ CastTarget { prefix: [None; 8], prefix_chunk_size: Size::ZERO, rest: uniform }
}
}
pub fn pair(a: Reg, b: Reg) -> CastTarget {
CastTarget {
prefix: [Some(a.kind), None, None, None, None, None, None, None],
- prefix_chunk: a.size,
+ prefix_chunk_size: a.size,
rest: Uniform::from(b),
}
}
pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
- (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
+ (self.prefix_chunk_size * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
.align_to(self.rest.align(cx))
+ self.rest.total
}
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
self.prefix
.iter()
- .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
+ .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk_size }.align(cx)))
.fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
acc.max(align)
})
let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
- self.mode = PassMode::Indirect(attrs, extra_attrs);
+ self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false };
}
pub fn make_indirect_byval(&mut self) {
self.make_indirect();
match self.mode {
- PassMode::Indirect(ref mut attrs, _) => {
- attrs.set(ArgAttribute::ByVal);
+ PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => {
+ *on_stack = true;
}
_ => unreachable!(),
}
if let abi::Int(i, signed) = scalar.value {
if i.size().bits() < bits {
if let PassMode::Direct(ref mut attrs) = self.mode {
- attrs.set(if signed { ArgAttribute::SExt } else { ArgAttribute::ZExt });
+ if signed {
+ attrs.ext(ArgExtension::Sext)
+ } else {
+ attrs.ext(ArgExtension::Zext)
+ };
}
}
}
}
pub fn is_indirect(&self) -> bool {
- matches!(self.mode, PassMode::Indirect(..))
+ matches!(self.mode, PassMode::Indirect {..})
}
pub fn is_sized_indirect(&self) -> bool {
- matches!(self.mode, PassMode::Indirect(_, None))
+ matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ })
}
pub fn is_unsized_indirect(&self) -> bool {
- matches!(self.mode, PassMode::Indirect(_, Some(_)))
+ matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ })
}
pub fn is_ignore(&self) -> bool {
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
}
- if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
- attrs.set(ArgAttribute::StructRet);
- }
-
Ok(())
}
}
// Reference: Clang RISC-V ELF psABI lowering code
// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
-use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
use crate::abi::{
self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods,
};
// 32-bit integers are always sign-extended
if i.size().bits() == 32 && xlen > 32 {
if let PassMode::Direct(ref mut attrs) = arg.mode {
- attrs.set(ArgAttribute::SExt);
+ attrs.ext(ArgExtension::Sext);
return;
}
}
for arg in &mut fn_abi.args {
let attrs = match arg.mode {
- PassMode::Ignore | PassMode::Indirect(_, None) => continue,
+ PassMode::Ignore
+ | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+ continue;
+ }
PassMode::Direct(ref mut attrs) => attrs,
- PassMode::Pair(..) | PassMode::Indirect(_, Some(_)) | PassMode::Cast(_) => {
+ PassMode::Pair(..)
+ | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
+ | PassMode::Cast(_) => {
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
}
};
--- /dev/null
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+ let base = opts("ios", Arch::Arm64_macabi);
+ Target {
+ llvm_target: "arm64-apple-ios-macabi".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ options: TargetOptions {
+ features: "+neon,+fp-armv8,+apple-a7".to_string(),
+ eliminate_frame_pointer: false,
+ max_atomic_width: Some(128),
+ unsupported_abis: super::arm_base::unsupported_abis(),
+ forces_embed_bitcode: true,
+ // Taken from a clang build on Xcode 11.4.1.
+ // These arguments are not actually invoked - they just have
+ // to look right to pass App Store validation.
+ bitcode_llvm_cmdline: "-triple\0\
+ arm64-apple-ios-macabi\0\
+ -emit-obj\0\
+ -disable-llvm-passes\0\
+ -target-abi\0\
+ darwinpcs\0\
+ -Os\0"
+ .to_string(),
+ ..base
+ },
+ }
+}
+++ /dev/null
-use crate::spec::Target;
-
-pub fn target() -> Target {
- let mut base = super::cloudabi_base::opts();
- base.max_atomic_width = Some(128);
- base.unsupported_abis = super::arm_base::unsupported_abis();
- base.linker = Some("aarch64-unknown-cloudabi-cc".to_string());
-
- Target {
- llvm_target: "aarch64-unknown-cloudabi".to_string(),
- pointer_width: 64,
- data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
- arch: "aarch64".to_string(),
- options: base,
- }
-}
I386,
X86_64,
X86_64_macabi,
+ Arm64_macabi,
}
fn target_cpu(arch: Arch) -> String {
I386 => "yonah",
X86_64 => "core2",
X86_64_macabi => "core2",
+ Arm64_macabi => "apple-a12",
}
.to_string()
}
fn link_env_remove(arch: Arch) -> Vec<String> {
match arch {
Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()],
- X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()],
+ X86_64_macabi | Arm64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()],
}
}
+++ /dev/null
-use crate::spec::{Target, TargetOptions};
-
-pub fn target() -> Target {
- let mut base = super::cloudabi_base::opts();
- base.cpu = "cortex-a8".to_string();
- base.max_atomic_width = Some(64);
- base.features = "+v7,+vfp3,+neon".to_string();
- base.unsupported_abis = super::arm_base::unsupported_abis();
- base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string());
-
- Target {
- llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
- pointer_width: 32,
- data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
- arch: "arm".to_string(),
- options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base },
- }
-}
+++ /dev/null
-use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions, TlsModel};
-
-pub fn opts() -> TargetOptions {
- let mut args = LinkArgs::new();
- args.insert(
- LinkerFlavor::Gcc,
- vec![
- "-Wl,-Bstatic".to_string(),
- "-Wl,--no-dynamic-linker".to_string(),
- "-Wl,--gc-sections".to_string(),
- ],
- );
-
- TargetOptions {
- os: "cloudabi".to_string(),
- executables: true,
- os_family: None,
- linker_is_gnu: true,
- pre_link_args: args,
- position_independent_executables: true,
- // As CloudABI only supports static linkage, there is no need
- // for dynamic TLS. The C library therefore does not provide
- // __tls_get_addr(), which is normally used to perform dynamic
- // TLS lookups by programs that make use of dlopen(). Only the
- // "local-exec" and "initial-exec" TLS models can be used.
- //
- // "local-exec" is more efficient than "initial-exec", as the
- // latter has one more level of indirection: it accesses the GOT
- // (Global Offset Table) to obtain the effective address of a
- // thread-local variable. Using a GOT is useful only when doing
- // dynamic linking.
- tls_model: TlsModel::LocalExec,
- relro_level: RelroLevel::Full,
- ..Default::default()
- }
-}
+++ /dev/null
-use crate::spec::{LinkerFlavor, Target};
-
-pub fn target() -> Target {
- let mut base = super::cloudabi_base::opts();
- base.cpu = "pentium4".to_string();
- base.max_atomic_width = Some(64);
- base.linker = Some("i686-unknown-cloudabi-cc".to_string());
- base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
- base.stack_probes = true;
-
- Target {
- llvm_target: "i686-unknown-cloudabi".to_string(),
- pointer_width: 32,
- data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
- f64:32:64-f80:32-n8:16:32-S128"
- .to_string(),
- arch: "x86".to_string(),
- options: base,
- }
-}
mod apple_sdk_base;
mod arm_base;
mod avr_gnu_base;
-mod cloudabi_base;
mod dragonfly_base;
mod freebsd_base;
mod fuchsia_base;
("armv7-apple-ios", armv7_apple_ios),
("armv7s-apple-ios", armv7s_apple_ios),
("x86_64-apple-ios-macabi", x86_64_apple_ios_macabi),
+ ("aarch64-apple-ios-macabi", aarch64_apple_ios_macabi),
("aarch64-apple-tvos", aarch64_apple_tvos),
("x86_64-apple-tvos", x86_64_apple_tvos),
("msp430-none-elf", msp430_none_elf),
- ("aarch64-unknown-cloudabi", aarch64_unknown_cloudabi),
- ("armv7-unknown-cloudabi-eabihf", armv7_unknown_cloudabi_eabihf),
- ("i686-unknown-cloudabi", i686_unknown_cloudabi),
- ("x86_64-unknown-cloudabi", x86_64_unknown_cloudabi),
-
("aarch64-unknown-hermit", aarch64_unknown_hermit),
("x86_64-unknown-hermit", x86_64_unknown_hermit),
("x86_64-unknown-hermit-kernel", x86_64_unknown_hermit_kernel),
+++ /dev/null
-use crate::spec::{LinkerFlavor, Target};
-
-pub fn target() -> Target {
- let mut base = super::cloudabi_base::opts();
- base.cpu = "x86-64".to_string();
- base.max_atomic_width = Some(64);
- base.linker = Some("x86_64-unknown-cloudabi-cc".to_string());
- base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
-
- Target {
- llvm_target: "x86_64-unknown-cloudabi".to_string(),
- pointer_width: 64,
- data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
- .to_string(),
- arch: "x86_64".to_string(),
- options: base,
- }
-}
&obligation.predicate,
&obligation.cause.code,
&mut vec![],
+ &mut Default::default(),
);
err.emit();
&obligation.predicate,
&obligation.cause.code,
&mut vec![],
+ &mut Default::default(),
);
self.suggest_unsized_bound_if_applicable(err, obligation);
}
use crate::infer::InferCtxt;
use crate::traits::normalize_projection_type;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
use rustc_hir as hir;
predicate: &T,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ seen_requirements: &mut FxHashSet<DefId>,
) where
T: fmt::Display;
&obligation.predicate,
next_code.unwrap(),
&mut Vec::new(),
+ &mut Default::default(),
);
}
predicate: &T,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ seen_requirements: &mut FxHashSet<DefId>,
) where
T: fmt::Display,
{
&parent_predicate,
&data.parent_code,
obligated_types,
+ seen_requirements,
)
});
}
}
ObligationCauseCode::ImplDerivedObligation(ref data) => {
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+ let mut parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+ let parent_def_id = parent_trait_ref.def_id();
err.note(&format!(
"required because of the requirements on the impl of `{}` for `{}`",
parent_trait_ref.print_only_trait_path(),
parent_trait_ref.skip_binder().self_ty()
));
- let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+
+ let mut parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+ let mut data = data;
+ let mut count = 0;
+ seen_requirements.insert(parent_def_id);
+ while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code {
+ // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`.
+ let child_trait_ref = self.resolve_vars_if_possible(child.parent_trait_ref);
+ let child_def_id = child_trait_ref.def_id();
+ if seen_requirements.insert(child_def_id) {
+ break;
+ }
+ count += 1;
+ data = child;
+ parent_predicate = child_trait_ref.without_const().to_predicate(tcx);
+ parent_trait_ref = child_trait_ref;
+ }
+ if count > 0 {
+ err.note(&format!("{} redundant requirements hidden", count));
+ err.note(&format!(
+ "required because of the requirements on the impl of `{}` for `{}`",
+ parent_trait_ref.print_only_trait_path(),
+ parent_trait_ref.skip_binder().self_ty()
+ ));
+ }
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
&parent_predicate,
&data.parent_code,
obligated_types,
+ seen_requirements,
)
});
}
&parent_predicate,
&data.parent_code,
obligated_types,
+ seen_requirements,
)
});
}
ObligationCauseCode::CompareImplMethodObligation { .. } => {
err.note(&format!(
- "the requirement `{}` appears on the impl method \
- but not on the corresponding trait method",
+ "the requirement `{}` appears on the impl method but not on the corresponding \
+ trait method",
predicate
));
}
ObligationCauseCode::CompareImplTypeObligation { .. } => {
err.note(&format!(
- "the requirement `{}` appears on the associated impl type \
- but not on the corresponding associated trait type",
+ "the requirement `{}` appears on the associated impl type but not on the \
+ corresponding associated trait type",
predicate
));
}
// type.
//
// NOTE: This should be kept in sync with the similar code in
- // `rustc_ty::instance::resolve_associated_item()`.
+ // `rustc_ty_utils::instance::resolve_associated_item()`.
let node_item =
assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
.map_err(|ErrorReported| ())?;
// Micro-optimization: filter out predicates relating to different traits.
let matching_bounds =
- all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
+ all_bounds.filter(|p| p.value.def_id() == stack.obligation.predicate.def_id());
// Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in matching_bounds {
- let wc = self.evaluate_where_clause(stack, bound)?;
+ let wc = self.evaluate_where_clause(stack, bound.value)?;
if wc.may_apply() {
candidates.vec.push(ParamCandidate(bound));
}
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
+use rustc_hir::Constness;
use rustc_index::bit_set::GrowableBitSet;
use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
}
ParamCandidate(param) => {
- let obligations = self.confirm_param_candidate(obligation, param);
- Ok(ImplSource::Param(obligations))
+ let obligations = self.confirm_param_candidate(obligation, param.value);
+ Ok(ImplSource::Param(obligations, param.constness))
}
ImplCandidate(impl_def_id) => {
ProjectionCandidate(idx) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?;
- Ok(ImplSource::Param(obligations))
+ // FIXME(jschievink): constness
+ Ok(ImplSource::Param(obligations, Constness::NotConst))
}
ObjectCandidate(idx) => {
// This indicates something like `Trait + Send: Send`. In this case, we know that
// this holds because that's what the object type is telling us, and there's really
// no additional obligations to prove and no types in particular to unify, etc.
- Ok(ImplSource::Param(Vec::new()))
+ Ok(ImplSource::Param(Vec::new(), Constness::NotConst))
}
BuiltinUnsizeCandidate => {
obligations.extend(self.infcx.commit_if_ok(|_| {
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate)
+ .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)
})?);
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_hir::Constness;
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fast_reject;
(BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
(_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
- (ParamCandidate(..), ParamCandidate(..)) => false,
+ (ParamCandidate(other), ParamCandidate(victim)) => {
+ if other.value == victim.value && victim.constness == Constness::NotConst {
+ // Drop otherwise equivalent non-const candidates in favor of const candidates.
+ true
+ } else {
+ false
+ }
+ }
// Global bounds from the where clause should be ignored
// here (see issue #50825). Otherwise, we have a where
| TraitAliasCandidate(..)
| ObjectCandidate(_)
| ProjectionCandidate(_),
- ) => !is_global(cand),
+ ) => !is_global(&cand.value),
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(cand)
+ is_global(&cand.value)
}
(
ImplCandidate(_)
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(cand) && other.evaluation.must_apply_modulo_regions()
+ is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
}
(ProjectionCandidate(i), ProjectionCandidate(j))
type Item = &'o TraitObligationStack<'o, 'tcx>;
fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
- match self.head {
- Some(o) => {
- *self = o.previous;
- Some(o)
- }
- None => None,
- }
+ let o = self.head?;
+ *self = o.previous;
+ Some(o)
}
}
for (p, _) in predicates {
if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
- if Some(poly_trait_ref.def_id()) == sized_trait {
- types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
+ if Some(poly_trait_ref.value.def_id()) == sized_trait {
+ types_without_default_bounds.remove(poly_trait_ref.value.self_ty().skip_binder());
continue;
}
}
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
pred.subst_supertrait(tcx, &trait_ref)
.to_opt_poly_trait_ref()
- .map(|trait_ref| item.clone_and_push(trait_ref, *span))
+ .map(|trait_ref| item.clone_and_push(trait_ref.value, *span))
});
debug!("expand_trait_aliases: items={:?}", items.clone());
.predicates
.iter()
.filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
- .map(|trait_ref| trait_ref.def_id())
+ .map(|trait_ref| trait_ref.value.def_id())
.filter(|&super_def_id| visited.insert(super_def_id)),
);
Some(def_id)
let mut cause = cause.clone();
if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() {
let derived_cause = traits::DerivedObligationCause {
- parent_trait_ref,
+ parent_trait_ref: parent_trait_ref.value,
parent_code: Rc::new(obligation.cause.code.clone()),
};
cause.make_mut().code =
+++ /dev/null
-[package]
-authors = ["The Rust Project Developers"]
-name = "rustc_ty"
-version = "0.0.0"
-edition = "2018"
-
-[dependencies]
-tracing = "0.1"
-rustc_middle = { path = "../rustc_middle" }
-rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
-rustc_hir = { path = "../rustc_hir" }
-rustc_infer = { path = "../rustc_infer" }
-rustc_span = { path = "../rustc_span" }
-rustc_session = { path = "../rustc_session" }
-rustc_target = { path = "../rustc_target" }
-rustc_trait_selection = { path = "../rustc_trait_selection" }
+++ /dev/null
-//! Queries for checking whether a type implements one of a few common traits.
-
-use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::DUMMY_SP;
-use rustc_trait_selection::traits;
-
-fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- is_item_raw(tcx, query, LangItem::Copy)
-}
-
-fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- is_item_raw(tcx, query, LangItem::Sized)
-}
-
-fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- is_item_raw(tcx, query, LangItem::Freeze)
-}
-
-fn is_item_raw<'tcx>(
- tcx: TyCtxt<'tcx>,
- query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
- item: LangItem,
-) -> bool {
- let (param_env, ty) = query.into_parts();
- let trait_def_id = tcx.require_lang_item(item, None);
- tcx.infer_ctxt().enter(|infcx| {
- traits::type_known_to_meet_bound_modulo_regions(
- &infcx,
- param_env,
- ty,
- trait_def_id,
- DUMMY_SP,
- )
- })
-}
-
-pub(crate) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { is_copy_raw, is_sized_raw, is_freeze_raw, ..*providers };
-}
+++ /dev/null
-use rustc_errors::ErrorReported;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
-use rustc_span::{sym, DUMMY_SP};
-use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
-use traits::{translate_substs, Reveal};
-
-use tracing::debug;
-
-fn resolve_instance<'tcx>(
- tcx: TyCtxt<'tcx>,
- key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
-) -> Result<Option<Instance<'tcx>>, ErrorReported> {
- let (param_env, (did, substs)) = key.into_parts();
- if let Some(did) = did.as_local() {
- if let Some(param_did) = tcx.opt_const_param_of(did) {
- return tcx.resolve_instance_of_const_arg(param_env.and((did, param_did, substs)));
- }
- }
-
- inner_resolve_instance(tcx, param_env.and((ty::WithOptConstParam::unknown(did), substs)))
-}
-
-fn resolve_instance_of_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>,
-) -> Result<Option<Instance<'tcx>>, ErrorReported> {
- let (param_env, (did, const_param_did, substs)) = key.into_parts();
- inner_resolve_instance(
- tcx,
- param_env.and((
- ty::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) },
- substs,
- )),
- )
-}
-
-fn inner_resolve_instance<'tcx>(
- tcx: TyCtxt<'tcx>,
- key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>,
-) -> Result<Option<Instance<'tcx>>, ErrorReported> {
- let (param_env, (def, substs)) = key.into_parts();
-
- debug!("resolve(def={:?}, substs={:?})", def.did, substs);
- let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
- debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
- let item = tcx.associated_item(def.did);
- resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
- } else {
- let ty = tcx.type_of(def.def_id_for_type_of());
- let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
-
- let def = match *item_type.kind() {
- ty::FnDef(..)
- if {
- let f = item_type.fn_sig(tcx);
- f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic
- } =>
- {
- debug!(" => intrinsic");
- ty::InstanceDef::Intrinsic(def.did)
- }
- ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => {
- let ty = substs.type_at(0);
-
- if ty.needs_drop(tcx, param_env) {
- debug!(" => nontrivial drop glue");
- match *ty.kind() {
- ty::Closure(..)
- | ty::Generator(..)
- | ty::Tuple(..)
- | ty::Adt(..)
- | ty::Dynamic(..)
- | ty::Array(..)
- | ty::Slice(..) => {}
- // Drop shims can only be built from ADTs.
- _ => return Ok(None),
- }
-
- ty::InstanceDef::DropGlue(def_id, Some(ty))
- } else {
- debug!(" => trivial drop glue");
- ty::InstanceDef::DropGlue(def_id, None)
- }
- }
- _ => {
- debug!(" => free item");
- ty::InstanceDef::Item(def)
- }
- };
- Ok(Some(Instance { def, substs }))
- };
- debug!("resolve(def.did={:?}, substs={:?}) = {:?}", def.did, substs, result);
- result
-}
-
-fn resolve_associated_item<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_item: &ty::AssocItem,
- param_env: ty::ParamEnv<'tcx>,
- trait_id: DefId,
- rcvr_substs: SubstsRef<'tcx>,
-) -> Result<Option<Instance<'tcx>>, ErrorReported> {
- let def_id = trait_item.def_id;
- debug!(
- "resolve_associated_item(trait_item={:?}, \
- param_env={:?}, \
- trait_id={:?}, \
- rcvr_substs={:?})",
- def_id, param_env, trait_id, rcvr_substs
- );
-
- let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
- let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)))?;
-
- // Now that we know which impl is being used, we can dispatch to
- // the actual function:
- Ok(match vtbl {
- traits::ImplSource::UserDefined(impl_data) => {
- debug!(
- "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
- param_env, trait_item, rcvr_substs, impl_data
- );
- assert!(!rcvr_substs.needs_infer());
- assert!(!trait_ref.needs_infer());
-
- let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
- let trait_def = tcx.trait_def(trait_def_id);
- let leaf_def = trait_def
- .ancestors(tcx, impl_data.impl_def_id)?
- .leaf_def(tcx, trait_item.ident, trait_item.kind)
- .unwrap_or_else(|| {
- bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
- });
-
- let substs = tcx.infer_ctxt().enter(|infcx| {
- let param_env = param_env.with_reveal_all_normalized(tcx);
- let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
- let substs = translate_substs(
- &infcx,
- param_env,
- impl_data.impl_def_id,
- substs,
- leaf_def.defining_node,
- );
- infcx.tcx.erase_regions(substs)
- });
-
- // Since this is a trait item, we need to see if the item is either a trait default item
- // or a specialization because we can't resolve those unless we can `Reveal::All`.
- // NOTE: This should be kept in sync with the similar code in
- // `rustc_trait_selection::traits::project::assemble_candidates_from_impls()`.
- let eligible = if leaf_def.is_final() {
- // Non-specializable items are always projectable.
- true
- } else {
- // Only reveal a specializable default if we're past type-checking
- // and the obligation is monomorphic, otherwise passes such as
- // transmute checking and polymorphic MIR optimizations could
- // get a result which isn't correct for all monomorphizations.
- if param_env.reveal() == Reveal::All {
- !trait_ref.still_further_specializable()
- } else {
- false
- }
- };
-
- if !eligible {
- return Ok(None);
- }
-
- let substs = tcx.erase_regions(substs);
-
- // Check if we just resolved an associated `const` declaration from
- // a `trait` to an associated `const` definition in an `impl`, where
- // the definition in the `impl` has the wrong type (for which an
- // error has already been/will be emitted elsewhere).
- //
- // NB: this may be expensive, we try to skip it in all the cases where
- // we know the error would've been caught (e.g. in an upstream crate).
- //
- // A better approach might be to just introduce a query (returning
- // `Result<(), ErrorReported>`) for the check that `rustc_typeck`
- // performs (i.e. that the definition's type in the `impl` matches
- // the declaration in the `trait`), so that we can cheaply check
- // here if it failed, instead of approximating it.
- if trait_item.kind == ty::AssocKind::Const
- && trait_item.def_id != leaf_def.item.def_id
- && leaf_def.item.def_id.is_local()
- {
- let normalized_type_of = |def_id, substs| {
- tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
- };
-
- let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs);
- let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
-
- if original_ty != resolved_ty {
- let msg = format!(
- "Instance::resolve: inconsistent associated `const` type: \
- was `{}: {}` but resolved to `{}: {}`",
- tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs),
- original_ty,
- tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
- resolved_ty,
- );
- let span = tcx.def_span(leaf_def.item.def_id);
- tcx.sess.delay_span_bug(span, &msg);
-
- return Err(ErrorReported);
- }
- }
-
- Some(ty::Instance::new(leaf_def.item.def_id, substs))
- }
- traits::ImplSource::Generator(generator_data) => Some(Instance {
- def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
- generator_data.generator_def_id,
- )),
- substs: generator_data.substs,
- }),
- traits::ImplSource::Closure(closure_data) => {
- let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap();
- Some(Instance::resolve_closure(
- tcx,
- closure_data.closure_def_id,
- closure_data.substs,
- trait_closure_kind,
- ))
- }
- traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
- def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
- substs: rcvr_substs,
- }),
- _ => None,
- },
- traits::ImplSource::Object(ref data) => {
- let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
- Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
- }
- traits::ImplSource::Builtin(..) => {
- if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
- // FIXME(eddyb) use lang items for methods instead of names.
- let name = tcx.item_name(def_id);
- if name == sym::clone {
- let self_ty = trait_ref.self_ty();
-
- let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
- match self_ty.kind() {
- _ if is_copy => (),
- ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
- _ => return Ok(None),
- };
-
- Some(Instance {
- def: ty::InstanceDef::CloneShim(def_id, self_ty),
- substs: rcvr_substs,
- })
- } else {
- assert_eq!(name, sym::clone_from);
-
- // Use the default `fn clone_from` from `trait Clone`.
- let substs = tcx.erase_regions(rcvr_substs);
- Some(ty::Instance::new(def_id, substs))
- }
- } else {
- None
- }
- }
- traits::ImplSource::AutoImpl(..)
- | traits::ImplSource::Param(..)
- | traits::ImplSource::TraitAlias(..)
- | traits::ImplSource::DiscriminantKind(..) => None,
- })
-}
-
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers =
- ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers };
-}
+++ /dev/null
-//! Various checks
-//!
-//! # Note
-//!
-//! This API is completely unstable and subject to change.
-
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(nll)]
-#![recursion_limit = "256"]
-
-#[macro_use]
-extern crate rustc_middle;
-#[macro_use]
-extern crate tracing;
-
-use rustc_middle::ty::query::Providers;
-
-mod common_traits;
-pub mod instance;
-mod needs_drop;
-mod ty;
-
-pub fn provide(providers: &mut Providers) {
- common_traits::provide(providers);
- needs_drop::provide(providers);
- ty::provide(providers);
- instance::provide(providers);
-}
+++ /dev/null
-//! Check whether a type has (potentially) non-trivial drop glue.
-
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::Limit;
-use rustc_span::DUMMY_SP;
-
-type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
-
-fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- let adt_fields =
- move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
- // If we don't know a type doesn't need drop, for example if it's a type
- // parameter without a `Copy` bound, then we conservatively return that it
- // needs drop.
- let res = NeedsDropTypes::new(tcx, query.param_env, query.value, adt_fields).next().is_some();
- debug!("needs_drop_raw({:?}) = {:?}", query, res);
- res
-}
-
-struct NeedsDropTypes<'tcx, F> {
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- query_ty: Ty<'tcx>,
- seen_tys: FxHashSet<Ty<'tcx>>,
- /// A stack of types left to process, and the recursion depth when we
- /// pushed that type. Each round, we pop something from the stack and check
- /// if it needs drop. If the result depends on whether some other types
- /// need drop we push them onto the stack.
- unchecked_tys: Vec<(Ty<'tcx>, usize)>,
- recursion_limit: Limit,
- adt_components: F,
-}
-
-impl<'tcx, F> NeedsDropTypes<'tcx, F> {
- fn new(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ty: Ty<'tcx>,
- adt_components: F,
- ) -> Self {
- let mut seen_tys = FxHashSet::default();
- seen_tys.insert(ty);
- Self {
- tcx,
- param_env,
- seen_tys,
- query_ty: ty,
- unchecked_tys: vec![(ty, 0)],
- recursion_limit: tcx.sess.recursion_limit(),
- adt_components,
- }
- }
-}
-
-impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
-where
- F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
- I: Iterator<Item = Ty<'tcx>>,
-{
- type Item = NeedsDropResult<Ty<'tcx>>;
-
- fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
- let tcx = self.tcx;
-
- while let Some((ty, level)) = self.unchecked_tys.pop() {
- if !self.recursion_limit.value_within_limit(level) {
- // Not having a `Span` isn't great. But there's hopefully some other
- // recursion limit error as well.
- tcx.sess.span_err(
- DUMMY_SP,
- &format!("overflow while checking whether `{}` requires drop", self.query_ty),
- );
- return Some(Err(AlwaysRequiresDrop));
- }
-
- let components = match needs_drop_components(ty, &tcx.data_layout) {
- Err(e) => return Some(Err(e)),
- Ok(components) => components,
- };
- debug!("needs_drop_components({:?}) = {:?}", ty, components);
-
- let queue_type = move |this: &mut Self, component: Ty<'tcx>| {
- if this.seen_tys.insert(component) {
- this.unchecked_tys.push((component, level + 1));
- }
- };
-
- for component in components {
- match *component.kind() {
- _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
-
- ty::Closure(_, substs) => {
- for upvar_ty in substs.as_closure().upvar_tys() {
- queue_type(self, upvar_ty);
- }
- }
-
- ty::Generator(def_id, substs, _) => {
- let substs = substs.as_generator();
- for upvar_ty in substs.upvar_tys() {
- queue_type(self, upvar_ty);
- }
-
- let witness = substs.witness();
- let interior_tys = match witness.kind() {
- &ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys),
- _ => {
- tcx.sess.delay_span_bug(
- tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP),
- &format!("unexpected generator witness type {:?}", witness),
- );
- return Some(Err(AlwaysRequiresDrop));
- }
- };
-
- for interior_ty in interior_tys {
- queue_type(self, interior_ty);
- }
- }
-
- // Check for a `Drop` impl and whether this is a union or
- // `ManuallyDrop`. If it's a struct or enum without a `Drop`
- // impl then check whether the field types need `Drop`.
- ty::Adt(adt_def, substs) => {
- let tys = match (self.adt_components)(adt_def) {
- Err(e) => return Some(Err(e)),
- Ok(tys) => tys,
- };
- for required_ty in tys {
- let subst_ty = tcx.normalize_erasing_regions(
- self.param_env,
- required_ty.subst(tcx, substs),
- );
- queue_type(self, subst_ty);
- }
- }
- ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => {
- if ty == component {
- // Return the type to the caller: they may be able
- // to normalize further than we can.
- return Some(Ok(component));
- } else {
- // Store the type for later. We can't return here
- // because we would then lose any other components
- // of the type.
- queue_type(self, component);
- }
- }
- _ => return Some(Err(AlwaysRequiresDrop)),
- }
- }
- }
-
- None
- }
-}
-
-fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_components = move |adt_def: &ty::AdtDef| {
- if adt_def.is_manually_drop() {
- debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
- return Ok(Vec::new().into_iter());
- } else if adt_def.destructor(tcx).is_some() {
- debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
- return Err(AlwaysRequiresDrop);
- } else if adt_def.is_union() {
- debug!("adt_drop_tys: `{:?}` is a union", adt_def);
- return Ok(Vec::new().into_iter());
- }
- Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>().into_iter())
- };
-
- let adt_ty = tcx.type_of(def_id);
- let param_env = tcx.param_env(def_id);
- let res: Result<Vec<_>, _> =
- NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect();
-
- debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res);
- res.map(|components| tcx.intern_type_list(&components))
-}
-
-pub(crate) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { needs_drop_raw, adt_drop_tys, ..*providers };
-}
+++ /dev/null
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::svh::Svh;
-use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_middle::hir::map as hir_map;
-use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{
- self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
-};
-use rustc_session::CrateDisambiguator;
-use rustc_span::symbol::Symbol;
-use rustc_span::Span;
-use rustc_trait_selection::traits;
-
-fn sized_constraint_for_ty<'tcx>(
- tcx: TyCtxt<'tcx>,
- adtdef: &ty::AdtDef,
- ty: Ty<'tcx>,
-) -> Vec<Ty<'tcx>> {
- use ty::TyKind::*;
-
- let result = match ty.kind() {
- Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
- | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],
-
- Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => {
- // these are never sized - return the target type
- vec![ty]
- }
-
- Tuple(ref tys) => match tys.last() {
- None => vec![],
- Some(ty) => sized_constraint_for_ty(tcx, adtdef, ty.expect_ty()),
- },
-
- Adt(adt, substs) => {
- // recursive case
- let adt_tys = adt.sized_constraint(tcx);
- debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
- adt_tys
- .iter()
- .map(|ty| ty.subst(tcx, substs))
- .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
- .collect()
- }
-
- Projection(..) | Opaque(..) => {
- // must calculate explicitly.
- // FIXME: consider special-casing always-Sized projections
- vec![ty]
- }
-
- Param(..) => {
- // perf hack: if there is a `T: Sized` bound, then
- // we know that `T` is Sized and do not need to check
- // it on the impl.
-
- let sized_trait = match tcx.lang_items().sized_trait() {
- Some(x) => x,
- _ => return vec![ty],
- };
- let sized_predicate = ty::Binder::dummy(ty::TraitRef {
- def_id: sized_trait,
- substs: tcx.mk_substs_trait(ty, &[]),
- })
- .without_const()
- .to_predicate(tcx);
- let predicates = tcx.predicates_of(adtdef.did).predicates;
- if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
- }
-
- Placeholder(..) | Bound(..) | Infer(..) => {
- bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty)
- }
- };
- debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
- result
-}
-
-fn associated_item_from_trait_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
- let def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
- let (kind, has_self) = match trait_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
- };
-
- ty::AssocItem {
- ident: trait_item_ref.ident,
- kind,
- vis: tcx.visibility(def_id),
- defaultness: trait_item_ref.defaultness,
- def_id: def_id.to_def_id(),
- container: ty::TraitContainer(parent_def_id.to_def_id()),
- fn_has_self_parameter: has_self,
- }
-}
-
-fn associated_item_from_impl_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- impl_item_ref: &hir::ImplItemRef<'_>,
-) -> ty::AssocItem {
- let def_id = tcx.hir().local_def_id(impl_item_ref.id.hir_id);
- let (kind, has_self) = match impl_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
- };
-
- ty::AssocItem {
- ident: impl_item_ref.ident,
- kind,
- vis: tcx.visibility(def_id),
- defaultness: impl_item_ref.defaultness,
- def_id: def_id.to_def_id(),
- container: ty::ImplContainer(parent_def_id.to_def_id()),
- fn_has_self_parameter: has_self,
- }
-}
-
-fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
- let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let parent_id = tcx.hir().get_parent_item(id);
- let parent_def_id = tcx.hir().local_def_id(parent_id);
- let parent_item = tcx.hir().expect_item(parent_id);
- match parent_item.kind {
- hir::ItemKind::Impl { ref items, .. } => {
- if let Some(impl_item_ref) = items.iter().find(|i| i.id.hir_id == id) {
- let assoc_item =
- associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
- debug_assert_eq!(assoc_item.def_id, def_id);
- return assoc_item;
- }
- }
-
- hir::ItemKind::Trait(.., ref trait_item_refs) => {
- if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.hir_id == id) {
- let assoc_item =
- associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
- debug_assert_eq!(assoc_item.def_id, def_id);
- return assoc_item;
- }
- }
-
- _ => {}
- }
-
- span_bug!(
- parent_item.span,
- "unexpected parent of trait or impl item or item not found: {:?}",
- parent_item.kind
- )
-}
-
-fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
- if let hir::ItemKind::Impl { defaultness, .. } = item.kind {
- defaultness
- } else {
- bug!("`impl_defaultness` called on {:?}", item);
- }
-}
-
-/// Calculates the `Sized` constraint.
-///
-/// In fact, there are only a few options for the types in the constraint:
-/// - an obviously-unsized type
-/// - a type parameter or projection whose Sizedness can't be known
-/// - a tuple of type parameters or projections, if there are multiple
-/// such.
-/// - a Error, if a type contained itself. The representability
-/// check should catch this case.
-fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
- let def = tcx.adt_def(def_id);
-
- let result = tcx.mk_type_list(
- def.variants
- .iter()
- .flat_map(|v| v.fields.last())
- .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did))),
- );
-
- debug!("adt_sized_constraint: {:?} => {:?}", def, result);
-
- ty::AdtSizedConstraint(result)
-}
-
-fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
- let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(id);
- match item.kind {
- hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
- trait_item_refs
- .iter()
- .map(|trait_item_ref| trait_item_ref.id)
- .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
- ),
- hir::ItemKind::Impl { ref items, .. } => tcx.arena.alloc_from_iter(
- items
- .iter()
- .map(|impl_item_ref| impl_item_ref.id)
- .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
- ),
- hir::ItemKind::TraitAlias(..) => &[],
- _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
- }
-}
-
-fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssociatedItems<'_> {
- let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
- ty::AssociatedItems::new(items)
-}
-
-fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
- tcx.hir().span_if_local(def_id).unwrap()
-}
-
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
- tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
- ty::TraitContainer(def_id) => Some(def_id),
- ty::ImplContainer(_) => None,
- })
-}
-
-/// See `ParamEnv` struct definition for details.
-fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
- // The param_env of an impl Trait type is its defining function's param_env
- if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
- return param_env(tcx, parent);
- }
- // Compute the bounds on Self and the type parameters.
-
- let ty::InstantiatedPredicates { mut predicates, .. } =
- tcx.predicates_of(def_id).instantiate_identity(tcx);
-
- // Finally, we have to normalize the bounds in the environment, in
- // case they contain any associated type projections. This process
- // can yield errors if the put in illegal associated types, like
- // `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We
- // report these errors right here; this doesn't actually feel
- // right to me, because constructing the environment feels like a
- // kind of a "idempotent" action, but I'm not sure where would be
- // a better place. In practice, we construct environments for
- // every fn once during type checking, and we'll abort if there
- // are any errors at that point, so after type checking you can be
- // sure that this will succeed without errors anyway.
-
- if tcx.sess.opts.debugging_opts.chalk {
- let environment = well_formed_types_in_env(tcx, def_id);
- predicates.extend(environment);
- }
-
- let unnormalized_env =
- ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
-
- let body_id = def_id
- .as_local()
- .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
- .map_or(hir::CRATE_HIR_ID, |id| {
- tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
- });
- let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
- traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
-}
-
-/// Elaborate the environment.
-///
-/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s
-/// that are assumed to be well-formed (because they come from the environment).
-///
-/// Used only in chalk mode.
-fn well_formed_types_in_env<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
-) -> &'tcx ty::List<Predicate<'tcx>> {
- use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
- use rustc_middle::ty::subst::GenericArgKind;
-
- debug!("environment(def_id = {:?})", def_id);
-
- // The environment of an impl Trait type is its defining function's environment.
- if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
- return well_formed_types_in_env(tcx, parent);
- }
-
- // Compute the bounds on `Self` and the type parameters.
- let ty::InstantiatedPredicates { predicates, .. } =
- tcx.predicates_of(def_id).instantiate_identity(tcx);
-
- let clauses = predicates.into_iter();
-
- if !def_id.is_local() {
- return ty::List::empty();
- }
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let node = tcx.hir().get(hir_id);
-
- enum NodeKind {
- TraitImpl,
- InherentImpl,
- Fn,
- Other,
- };
-
- let node_kind = match node {
- Node::TraitItem(item) => match item.kind {
- TraitItemKind::Fn(..) => NodeKind::Fn,
- _ => NodeKind::Other,
- },
-
- Node::ImplItem(item) => match item.kind {
- ImplItemKind::Fn(..) => NodeKind::Fn,
- _ => NodeKind::Other,
- },
-
- Node::Item(item) => match item.kind {
- ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl,
- ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl,
- ItemKind::Fn(..) => NodeKind::Fn,
- _ => NodeKind::Other,
- },
-
- Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Fn(..) => NodeKind::Fn,
- _ => NodeKind::Other,
- },
-
- // FIXME: closures?
- _ => NodeKind::Other,
- };
-
- // FIXME(eddyb) isn't the unordered nature of this a hazard?
- let mut inputs = FxIndexSet::default();
-
- match node_kind {
- // In a trait impl, we assume that the header trait ref and all its
- // constituents are well-formed.
- NodeKind::TraitImpl => {
- let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
-
- // FIXME(chalk): this has problems because of late-bound regions
- //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
- inputs.extend(trait_ref.substs.iter());
- }
-
- // In an inherent impl, we assume that the receiver type and all its
- // constituents are well-formed.
- NodeKind::InherentImpl => {
- let self_ty = tcx.type_of(def_id);
- inputs.extend(self_ty.walk());
- }
-
- // In an fn, we assume that the arguments and all their constituents are
- // well-formed.
- NodeKind::Fn => {
- let fn_sig = tcx.fn_sig(def_id);
- let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
-
- inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
- }
-
- NodeKind::Other => (),
- }
- let input_clauses = inputs.into_iter().filter_map(|arg| {
- match arg.unpack() {
- GenericArgKind::Type(ty) => {
- let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty));
- Some(tcx.mk_predicate(PredicateKind::ForAll(binder)))
- }
-
- // FIXME(eddyb) no WF conditions from lifetimes?
- GenericArgKind::Lifetime(_) => None,
-
- // FIXME(eddyb) support const generics in Chalk
- GenericArgKind::Const(_) => None,
- }
- });
-
- tcx.mk_predicates(clauses.chain(input_clauses))
-}
-
-fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
- tcx.param_env(def_id).with_reveal_all_normalized(tcx)
-}
-
-fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
- assert_eq!(crate_num, LOCAL_CRATE);
- tcx.sess.local_crate_disambiguator()
-}
-
-fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
- assert_eq!(crate_num, LOCAL_CRATE);
- tcx.crate_name
-}
-
-fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
- tcx.index_hir(crate_num).crate_hash
-}
-
-fn instance_def_size_estimate<'tcx>(
- tcx: TyCtxt<'tcx>,
- instance_def: ty::InstanceDef<'tcx>,
-) -> usize {
- use ty::InstanceDef;
-
- match instance_def {
- InstanceDef::Item(..) | InstanceDef::DropGlue(..) => {
- let mir = tcx.instance_mir(instance_def);
- mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum()
- }
- // Estimate the size of other compiler-generated shims to be 1.
- _ => 1,
- }
-}
-
-/// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`.
-///
-/// See [`ty::ImplOverlapKind::Issue33140`] for more details.
-fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
- debug!("issue33140_self_ty({:?})", def_id);
-
- let trait_ref = tcx
- .impl_trait_ref(def_id)
- .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));
-
- debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
-
- let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive
- && tcx.associated_item_def_ids(trait_ref.def_id).is_empty();
-
- // Check whether these impls would be ok for a marker trait.
- if !is_marker_like {
- debug!("issue33140_self_ty - not marker-like!");
- return None;
- }
-
- // impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
- if trait_ref.substs.len() != 1 {
- debug!("issue33140_self_ty - impl has substs!");
- return None;
- }
-
- let predicates = tcx.predicates_of(def_id);
- if predicates.parent.is_some() || !predicates.predicates.is_empty() {
- debug!("issue33140_self_ty - impl has predicates {:?}!", predicates);
- return None;
- }
-
- let self_ty = trait_ref.self_ty();
- let self_ty_matches = match self_ty.kind() {
- ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
- _ => false,
- };
-
- if self_ty_matches {
- debug!("issue33140_self_ty - MATCHES!");
- Some(self_ty)
- } else {
- debug!("issue33140_self_ty - non-matching self type");
- None
- }
-}
-
-/// Check if a function is async.
-fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
- let node = tcx.hir().get(hir_id);
-
- let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
- bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
- });
-
- fn_like.asyncness()
-}
-
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
- asyncness,
- associated_item,
- associated_item_def_ids,
- associated_items,
- adt_sized_constraint,
- def_span,
- param_env,
- param_env_reveal_all_normalized,
- trait_of_item,
- crate_disambiguator,
- original_crate_name,
- crate_hash,
- instance_def_size_estimate,
- issue33140_self_ty,
- impl_defaultness,
- ..*providers
- };
-}
--- /dev/null
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_ty_utils"
+version = "0.0.0"
+edition = "2018"
+
+[dependencies]
+tracing = "0.1"
+rustc_middle = { path = "../rustc_middle" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_span = { path = "../rustc_span" }
+rustc_session = { path = "../rustc_session" }
+rustc_target = { path = "../rustc_target" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
--- /dev/null
+//! Queries for checking whether a type implements one of a few common traits.
+
+use rustc_hir::lang_items::LangItem;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::DUMMY_SP;
+use rustc_trait_selection::traits;
+
+fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ is_item_raw(tcx, query, LangItem::Copy)
+}
+
+fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ is_item_raw(tcx, query, LangItem::Sized)
+}
+
+fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ is_item_raw(tcx, query, LangItem::Freeze)
+}
+
+fn is_item_raw<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+ item: LangItem,
+) -> bool {
+ let (param_env, ty) = query.into_parts();
+ let trait_def_id = tcx.require_lang_item(item, None);
+ tcx.infer_ctxt().enter(|infcx| {
+ traits::type_known_to_meet_bound_modulo_regions(
+ &infcx,
+ param_env,
+ ty,
+ trait_def_id,
+ DUMMY_SP,
+ )
+ })
+}
+
+pub(crate) fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers { is_copy_raw, is_sized_raw, is_freeze_raw, ..*providers };
+}
--- /dev/null
+use rustc_errors::ErrorReported;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
+use rustc_span::{sym, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
+use traits::{translate_substs, Reveal};
+
+use tracing::debug;
+
+fn resolve_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
+) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+ let (param_env, (did, substs)) = key.into_parts();
+ if let Some(did) = did.as_local() {
+ if let Some(param_did) = tcx.opt_const_param_of(did) {
+ return tcx.resolve_instance_of_const_arg(param_env.and((did, param_did, substs)));
+ }
+ }
+
+ inner_resolve_instance(tcx, param_env.and((ty::WithOptConstParam::unknown(did), substs)))
+}
+
+fn resolve_instance_of_const_arg<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>,
+) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+ let (param_env, (did, const_param_did, substs)) = key.into_parts();
+ inner_resolve_instance(
+ tcx,
+ param_env.and((
+ ty::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) },
+ substs,
+ )),
+ )
+}
+
+fn inner_resolve_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>,
+) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+ let (param_env, (def, substs)) = key.into_parts();
+
+ debug!("resolve(def={:?}, substs={:?})", def.did, substs);
+ let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
+ debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
+ let item = tcx.associated_item(def.did);
+ resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
+ } else {
+ let ty = tcx.type_of(def.def_id_for_type_of());
+ let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
+
+ let def = match *item_type.kind() {
+ ty::FnDef(..)
+ if {
+ let f = item_type.fn_sig(tcx);
+ f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic
+ } =>
+ {
+ debug!(" => intrinsic");
+ ty::InstanceDef::Intrinsic(def.did)
+ }
+ ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => {
+ let ty = substs.type_at(0);
+
+ if ty.needs_drop(tcx, param_env) {
+ debug!(" => nontrivial drop glue");
+ match *ty.kind() {
+ ty::Closure(..)
+ | ty::Generator(..)
+ | ty::Tuple(..)
+ | ty::Adt(..)
+ | ty::Dynamic(..)
+ | ty::Array(..)
+ | ty::Slice(..) => {}
+ // Drop shims can only be built from ADTs.
+ _ => return Ok(None),
+ }
+
+ ty::InstanceDef::DropGlue(def_id, Some(ty))
+ } else {
+ debug!(" => trivial drop glue");
+ ty::InstanceDef::DropGlue(def_id, None)
+ }
+ }
+ _ => {
+ debug!(" => free item");
+ ty::InstanceDef::Item(def)
+ }
+ };
+ Ok(Some(Instance { def, substs }))
+ };
+ debug!("resolve(def.did={:?}, substs={:?}) = {:?}", def.did, substs, result);
+ result
+}
+
+fn resolve_associated_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_item: &ty::AssocItem,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_id: DefId,
+ rcvr_substs: SubstsRef<'tcx>,
+) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+ let def_id = trait_item.def_id;
+ debug!(
+ "resolve_associated_item(trait_item={:?}, \
+ param_env={:?}, \
+ trait_id={:?}, \
+ rcvr_substs={:?})",
+ def_id, param_env, trait_id, rcvr_substs
+ );
+
+ let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
+ let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)))?;
+
+ // Now that we know which impl is being used, we can dispatch to
+ // the actual function:
+ Ok(match vtbl {
+ traits::ImplSource::UserDefined(impl_data) => {
+ debug!(
+ "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
+ param_env, trait_item, rcvr_substs, impl_data
+ );
+ assert!(!rcvr_substs.needs_infer());
+ assert!(!trait_ref.needs_infer());
+
+ let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
+ let trait_def = tcx.trait_def(trait_def_id);
+ let leaf_def = trait_def
+ .ancestors(tcx, impl_data.impl_def_id)?
+ .leaf_def(tcx, trait_item.ident, trait_item.kind)
+ .unwrap_or_else(|| {
+ bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
+ });
+
+ let substs = tcx.infer_ctxt().enter(|infcx| {
+ let param_env = param_env.with_reveal_all_normalized(tcx);
+ let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
+ let substs = translate_substs(
+ &infcx,
+ param_env,
+ impl_data.impl_def_id,
+ substs,
+ leaf_def.defining_node,
+ );
+ infcx.tcx.erase_regions(substs)
+ });
+
+ // Since this is a trait item, we need to see if the item is either a trait default item
+ // or a specialization because we can't resolve those unless we can `Reveal::All`.
+ // NOTE: This should be kept in sync with the similar code in
+ // `rustc_trait_selection::traits::project::assemble_candidates_from_impls()`.
+ let eligible = if leaf_def.is_final() {
+ // Non-specializable items are always projectable.
+ true
+ } else {
+ // Only reveal a specializable default if we're past type-checking
+ // and the obligation is monomorphic, otherwise passes such as
+ // transmute checking and polymorphic MIR optimizations could
+ // get a result which isn't correct for all monomorphizations.
+ if param_env.reveal() == Reveal::All {
+ !trait_ref.still_further_specializable()
+ } else {
+ false
+ }
+ };
+
+ if !eligible {
+ return Ok(None);
+ }
+
+ let substs = tcx.erase_regions(substs);
+
+ // Check if we just resolved an associated `const` declaration from
+ // a `trait` to an associated `const` definition in an `impl`, where
+ // the definition in the `impl` has the wrong type (for which an
+ // error has already been/will be emitted elsewhere).
+ //
+ // NB: this may be expensive, we try to skip it in all the cases where
+ // we know the error would've been caught (e.g. in an upstream crate).
+ //
+ // A better approach might be to just introduce a query (returning
+ // `Result<(), ErrorReported>`) for the check that `rustc_typeck`
+ // performs (i.e. that the definition's type in the `impl` matches
+ // the declaration in the `trait`), so that we can cheaply check
+ // here if it failed, instead of approximating it.
+ if trait_item.kind == ty::AssocKind::Const
+ && trait_item.def_id != leaf_def.item.def_id
+ && leaf_def.item.def_id.is_local()
+ {
+ let normalized_type_of = |def_id, substs| {
+ tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
+ };
+
+ let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs);
+ let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
+
+ if original_ty != resolved_ty {
+ let msg = format!(
+ "Instance::resolve: inconsistent associated `const` type: \
+ was `{}: {}` but resolved to `{}: {}`",
+ tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs),
+ original_ty,
+ tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
+ resolved_ty,
+ );
+ let span = tcx.def_span(leaf_def.item.def_id);
+ tcx.sess.delay_span_bug(span, &msg);
+
+ return Err(ErrorReported);
+ }
+ }
+
+ Some(ty::Instance::new(leaf_def.item.def_id, substs))
+ }
+ traits::ImplSource::Generator(generator_data) => Some(Instance {
+ def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
+ generator_data.generator_def_id,
+ )),
+ substs: generator_data.substs,
+ }),
+ traits::ImplSource::Closure(closure_data) => {
+ let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap();
+ Some(Instance::resolve_closure(
+ tcx,
+ closure_data.closure_def_id,
+ closure_data.substs,
+ trait_closure_kind,
+ ))
+ }
+ traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
+ ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
+ def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
+ substs: rcvr_substs,
+ }),
+ _ => None,
+ },
+ traits::ImplSource::Object(ref data) => {
+ let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
+ Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
+ }
+ traits::ImplSource::Builtin(..) => {
+ if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
+ // FIXME(eddyb) use lang items for methods instead of names.
+ let name = tcx.item_name(def_id);
+ if name == sym::clone {
+ let self_ty = trait_ref.self_ty();
+
+ let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
+ match self_ty.kind() {
+ _ if is_copy => (),
+ ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
+ _ => return Ok(None),
+ };
+
+ Some(Instance {
+ def: ty::InstanceDef::CloneShim(def_id, self_ty),
+ substs: rcvr_substs,
+ })
+ } else {
+ assert_eq!(name, sym::clone_from);
+
+ // Use the default `fn clone_from` from `trait Clone`.
+ let substs = tcx.erase_regions(rcvr_substs);
+ Some(ty::Instance::new(def_id, substs))
+ }
+ } else {
+ None
+ }
+ }
+ traits::ImplSource::AutoImpl(..)
+ | traits::ImplSource::Param(..)
+ | traits::ImplSource::TraitAlias(..)
+ | traits::ImplSource::DiscriminantKind(..) => None,
+ })
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers =
+ ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers };
+}
--- /dev/null
+//! Various checks
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(nll)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate rustc_middle;
+#[macro_use]
+extern crate tracing;
+
+use rustc_middle::ty::query::Providers;
+
+mod common_traits;
+pub mod instance;
+mod needs_drop;
+mod ty;
+
+pub fn provide(providers: &mut Providers) {
+ common_traits::provide(providers);
+ needs_drop::provide(providers);
+ ty::provide(providers);
+ instance::provide(providers);
+}
--- /dev/null
+//! Check whether a type has (potentially) non-trivial drop glue.
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::Limit;
+use rustc_span::DUMMY_SP;
+
+type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
+
+fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ let adt_fields =
+ move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
+ // If we don't know a type doesn't need drop, for example if it's a type
+ // parameter without a `Copy` bound, then we conservatively return that it
+ // needs drop.
+ let res = NeedsDropTypes::new(tcx, query.param_env, query.value, adt_fields).next().is_some();
+ debug!("needs_drop_raw({:?}) = {:?}", query, res);
+ res
+}
+
+struct NeedsDropTypes<'tcx, F> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ query_ty: Ty<'tcx>,
+ seen_tys: FxHashSet<Ty<'tcx>>,
+ /// A stack of types left to process, and the recursion depth when we
+ /// pushed that type. Each round, we pop something from the stack and check
+ /// if it needs drop. If the result depends on whether some other types
+ /// need drop we push them onto the stack.
+ unchecked_tys: Vec<(Ty<'tcx>, usize)>,
+ recursion_limit: Limit,
+ adt_components: F,
+}
+
+impl<'tcx, F> NeedsDropTypes<'tcx, F> {
+ fn new(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ adt_components: F,
+ ) -> Self {
+ let mut seen_tys = FxHashSet::default();
+ seen_tys.insert(ty);
+ Self {
+ tcx,
+ param_env,
+ seen_tys,
+ query_ty: ty,
+ unchecked_tys: vec![(ty, 0)],
+ recursion_limit: tcx.sess.recursion_limit(),
+ adt_components,
+ }
+ }
+}
+
+impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
+where
+ F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
+ I: Iterator<Item = Ty<'tcx>>,
+{
+ type Item = NeedsDropResult<Ty<'tcx>>;
+
+ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
+ let tcx = self.tcx;
+
+ while let Some((ty, level)) = self.unchecked_tys.pop() {
+ if !self.recursion_limit.value_within_limit(level) {
+ // Not having a `Span` isn't great. But there's hopefully some other
+ // recursion limit error as well.
+ tcx.sess.span_err(
+ DUMMY_SP,
+ &format!("overflow while checking whether `{}` requires drop", self.query_ty),
+ );
+ return Some(Err(AlwaysRequiresDrop));
+ }
+
+ let components = match needs_drop_components(ty, &tcx.data_layout) {
+ Err(e) => return Some(Err(e)),
+ Ok(components) => components,
+ };
+ debug!("needs_drop_components({:?}) = {:?}", ty, components);
+
+ let queue_type = move |this: &mut Self, component: Ty<'tcx>| {
+ if this.seen_tys.insert(component) {
+ this.unchecked_tys.push((component, level + 1));
+ }
+ };
+
+ for component in components {
+ match *component.kind() {
+ _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
+
+ ty::Closure(_, substs) => {
+ for upvar_ty in substs.as_closure().upvar_tys() {
+ queue_type(self, upvar_ty);
+ }
+ }
+
+ ty::Generator(def_id, substs, _) => {
+ let substs = substs.as_generator();
+ for upvar_ty in substs.upvar_tys() {
+ queue_type(self, upvar_ty);
+ }
+
+ let witness = substs.witness();
+ let interior_tys = match witness.kind() {
+ &ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys),
+ _ => {
+ tcx.sess.delay_span_bug(
+ tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP),
+ &format!("unexpected generator witness type {:?}", witness),
+ );
+ return Some(Err(AlwaysRequiresDrop));
+ }
+ };
+
+ for interior_ty in interior_tys {
+ queue_type(self, interior_ty);
+ }
+ }
+
+ // Check for a `Drop` impl and whether this is a union or
+ // `ManuallyDrop`. If it's a struct or enum without a `Drop`
+ // impl then check whether the field types need `Drop`.
+ ty::Adt(adt_def, substs) => {
+ let tys = match (self.adt_components)(adt_def) {
+ Err(e) => return Some(Err(e)),
+ Ok(tys) => tys,
+ };
+ for required_ty in tys {
+ let subst_ty = tcx.normalize_erasing_regions(
+ self.param_env,
+ required_ty.subst(tcx, substs),
+ );
+ queue_type(self, subst_ty);
+ }
+ }
+ ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => {
+ if ty == component {
+ // Return the type to the caller: they may be able
+ // to normalize further than we can.
+ return Some(Ok(component));
+ } else {
+ // Store the type for later. We can't return here
+ // because we would then lose any other components
+ // of the type.
+ queue_type(self, component);
+ }
+ }
+ _ => return Some(Err(AlwaysRequiresDrop)),
+ }
+ }
+ }
+
+ None
+ }
+}
+
+fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+ let adt_components = move |adt_def: &ty::AdtDef| {
+ if adt_def.is_manually_drop() {
+ debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
+ return Ok(Vec::new().into_iter());
+ } else if adt_def.destructor(tcx).is_some() {
+ debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+ return Err(AlwaysRequiresDrop);
+ } else if adt_def.is_union() {
+ debug!("adt_drop_tys: `{:?}` is a union", adt_def);
+ return Ok(Vec::new().into_iter());
+ }
+ Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>().into_iter())
+ };
+
+ let adt_ty = tcx.type_of(def_id);
+ let param_env = tcx.param_env(def_id);
+ let res: Result<Vec<_>, _> =
+ NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect();
+
+ debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res);
+ res.map(|components| tcx.intern_type_list(&components))
+}
+
+pub(crate) fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers { needs_drop_raw, adt_drop_tys, ..*providers };
+}
--- /dev/null
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::svh::Svh;
+use rustc_hir as hir;
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_middle::hir::map as hir_map;
+use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::{
+ self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
+};
+use rustc_session::CrateDisambiguator;
+use rustc_span::symbol::Symbol;
+use rustc_span::Span;
+use rustc_trait_selection::traits;
+
+fn sized_constraint_for_ty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ adtdef: &ty::AdtDef,
+ ty: Ty<'tcx>,
+) -> Vec<Ty<'tcx>> {
+ use ty::TyKind::*;
+
+ let result = match ty.kind() {
+ Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
+ | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],
+
+ Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => {
+ // these are never sized - return the target type
+ vec![ty]
+ }
+
+ Tuple(ref tys) => match tys.last() {
+ None => vec![],
+ Some(ty) => sized_constraint_for_ty(tcx, adtdef, ty.expect_ty()),
+ },
+
+ Adt(adt, substs) => {
+ // recursive case
+ let adt_tys = adt.sized_constraint(tcx);
+ debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
+ adt_tys
+ .iter()
+ .map(|ty| ty.subst(tcx, substs))
+ .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
+ .collect()
+ }
+
+ Projection(..) | Opaque(..) => {
+ // must calculate explicitly.
+ // FIXME: consider special-casing always-Sized projections
+ vec![ty]
+ }
+
+ Param(..) => {
+ // perf hack: if there is a `T: Sized` bound, then
+ // we know that `T` is Sized and do not need to check
+ // it on the impl.
+
+ let sized_trait = match tcx.lang_items().sized_trait() {
+ Some(x) => x,
+ _ => return vec![ty],
+ };
+ let sized_predicate = ty::Binder::dummy(ty::TraitRef {
+ def_id: sized_trait,
+ substs: tcx.mk_substs_trait(ty, &[]),
+ })
+ .without_const()
+ .to_predicate(tcx);
+ let predicates = tcx.predicates_of(adtdef.did).predicates;
+ if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
+ }
+
+ Placeholder(..) | Bound(..) | Infer(..) => {
+ bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty)
+ }
+ };
+ debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
+ result
+}
+
+fn associated_item_from_trait_item_ref(
+ tcx: TyCtxt<'_>,
+ parent_def_id: LocalDefId,
+ trait_item_ref: &hir::TraitItemRef,
+) -> ty::AssocItem {
+ let def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
+ let (kind, has_self) = match trait_item_ref.kind {
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ };
+
+ ty::AssocItem {
+ ident: trait_item_ref.ident,
+ kind,
+ vis: tcx.visibility(def_id),
+ defaultness: trait_item_ref.defaultness,
+ def_id: def_id.to_def_id(),
+ container: ty::TraitContainer(parent_def_id.to_def_id()),
+ fn_has_self_parameter: has_self,
+ }
+}
+
+fn associated_item_from_impl_item_ref(
+ tcx: TyCtxt<'_>,
+ parent_def_id: LocalDefId,
+ impl_item_ref: &hir::ImplItemRef<'_>,
+) -> ty::AssocItem {
+ let def_id = tcx.hir().local_def_id(impl_item_ref.id.hir_id);
+ let (kind, has_self) = match impl_item_ref.kind {
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ };
+
+ ty::AssocItem {
+ ident: impl_item_ref.ident,
+ kind,
+ vis: tcx.visibility(def_id),
+ defaultness: impl_item_ref.defaultness,
+ def_id: def_id.to_def_id(),
+ container: ty::ImplContainer(parent_def_id.to_def_id()),
+ fn_has_self_parameter: has_self,
+ }
+}
+
+fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let parent_id = tcx.hir().get_parent_item(id);
+ let parent_def_id = tcx.hir().local_def_id(parent_id);
+ let parent_item = tcx.hir().expect_item(parent_id);
+ match parent_item.kind {
+ hir::ItemKind::Impl { ref items, .. } => {
+ if let Some(impl_item_ref) = items.iter().find(|i| i.id.hir_id == id) {
+ let assoc_item =
+ associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+ debug_assert_eq!(assoc_item.def_id, def_id);
+ return assoc_item;
+ }
+ }
+
+ hir::ItemKind::Trait(.., ref trait_item_refs) => {
+ if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.hir_id == id) {
+ let assoc_item =
+ associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+ debug_assert_eq!(assoc_item.def_id, def_id);
+ return assoc_item;
+ }
+ }
+
+ _ => {}
+ }
+
+ span_bug!(
+ parent_item.span,
+ "unexpected parent of trait or impl item or item not found: {:?}",
+ parent_item.kind
+ )
+}
+
+fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let item = tcx.hir().expect_item(hir_id);
+ if let hir::ItemKind::Impl { defaultness, .. } = item.kind {
+ defaultness
+ } else {
+ bug!("`impl_defaultness` called on {:?}", item);
+ }
+}
+
+/// Calculates the `Sized` constraint.
+///
+/// In fact, there are only a few options for the types in the constraint:
+/// - an obviously-unsized type
+/// - a type parameter or projection whose Sizedness can't be known
+/// - a tuple of type parameters or projections, if there are multiple
+/// such.
+/// - a Error, if a type contained itself. The representability
+/// check should catch this case.
+fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
+ let def = tcx.adt_def(def_id);
+
+ let result = tcx.mk_type_list(
+ def.variants
+ .iter()
+ .flat_map(|v| v.fields.last())
+ .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did))),
+ );
+
+ debug!("adt_sized_constraint: {:?} => {:?}", def, result);
+
+ ty::AdtSizedConstraint(result)
+}
+
+fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let item = tcx.hir().expect_item(id);
+ match item.kind {
+ hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
+ trait_item_refs
+ .iter()
+ .map(|trait_item_ref| trait_item_ref.id)
+ .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
+ ),
+ hir::ItemKind::Impl { ref items, .. } => tcx.arena.alloc_from_iter(
+ items
+ .iter()
+ .map(|impl_item_ref| impl_item_ref.id)
+ .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
+ ),
+ hir::ItemKind::TraitAlias(..) => &[],
+ _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
+ }
+}
+
+fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssociatedItems<'_> {
+ let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
+ ty::AssociatedItems::new(items)
+}
+
+fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
+ tcx.hir().span_if_local(def_id).unwrap()
+}
+
+/// If the given `DefId` describes an item belonging to a trait,
+/// returns the `DefId` of the trait that the trait item belongs to;
+/// otherwise, returns `None`.
+fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
+ tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
+ ty::TraitContainer(def_id) => Some(def_id),
+ ty::ImplContainer(_) => None,
+ })
+}
+
+/// See `ParamEnv` struct definition for details.
+fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
+ // The param_env of an impl Trait type is its defining function's param_env
+ if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
+ return param_env(tcx, parent);
+ }
+ // Compute the bounds on Self and the type parameters.
+
+ let ty::InstantiatedPredicates { mut predicates, .. } =
+ tcx.predicates_of(def_id).instantiate_identity(tcx);
+
+ // Finally, we have to normalize the bounds in the environment, in
+ // case they contain any associated type projections. This process
+ // can yield errors if the put in illegal associated types, like
+ // `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We
+ // report these errors right here; this doesn't actually feel
+ // right to me, because constructing the environment feels like a
+ // kind of a "idempotent" action, but I'm not sure where would be
+ // a better place. In practice, we construct environments for
+ // every fn once during type checking, and we'll abort if there
+ // are any errors at that point, so after type checking you can be
+ // sure that this will succeed without errors anyway.
+
+ if tcx.sess.opts.debugging_opts.chalk {
+ let environment = well_formed_types_in_env(tcx, def_id);
+ predicates.extend(environment);
+ }
+
+ let unnormalized_env =
+ ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
+
+ let body_id = def_id
+ .as_local()
+ .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+ .map_or(hir::CRATE_HIR_ID, |id| {
+ tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
+ });
+ let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
+ traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
+}
+
+/// Elaborate the environment.
+///
+/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s
+/// that are assumed to be well-formed (because they come from the environment).
+///
+/// Used only in chalk mode.
+fn well_formed_types_in_env<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+) -> &'tcx ty::List<Predicate<'tcx>> {
+ use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
+ use rustc_middle::ty::subst::GenericArgKind;
+
+ debug!("environment(def_id = {:?})", def_id);
+
+ // The environment of an impl Trait type is its defining function's environment.
+ if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
+ return well_formed_types_in_env(tcx, parent);
+ }
+
+ // Compute the bounds on `Self` and the type parameters.
+ let ty::InstantiatedPredicates { predicates, .. } =
+ tcx.predicates_of(def_id).instantiate_identity(tcx);
+
+ let clauses = predicates.into_iter();
+
+ if !def_id.is_local() {
+ return ty::List::empty();
+ }
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let node = tcx.hir().get(hir_id);
+
+ enum NodeKind {
+ TraitImpl,
+ InherentImpl,
+ Fn,
+ Other,
+ }
+
+ let node_kind = match node {
+ Node::TraitItem(item) => match item.kind {
+ TraitItemKind::Fn(..) => NodeKind::Fn,
+ _ => NodeKind::Other,
+ },
+
+ Node::ImplItem(item) => match item.kind {
+ ImplItemKind::Fn(..) => NodeKind::Fn,
+ _ => NodeKind::Other,
+ },
+
+ Node::Item(item) => match item.kind {
+ ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl,
+ ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl,
+ ItemKind::Fn(..) => NodeKind::Fn,
+ _ => NodeKind::Other,
+ },
+
+ Node::ForeignItem(item) => match item.kind {
+ ForeignItemKind::Fn(..) => NodeKind::Fn,
+ _ => NodeKind::Other,
+ },
+
+ // FIXME: closures?
+ _ => NodeKind::Other,
+ };
+
+ // FIXME(eddyb) isn't the unordered nature of this a hazard?
+ let mut inputs = FxIndexSet::default();
+
+ match node_kind {
+ // In a trait impl, we assume that the header trait ref and all its
+ // constituents are well-formed.
+ NodeKind::TraitImpl => {
+ let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
+
+ // FIXME(chalk): this has problems because of late-bound regions
+ //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
+ inputs.extend(trait_ref.substs.iter());
+ }
+
+ // In an inherent impl, we assume that the receiver type and all its
+ // constituents are well-formed.
+ NodeKind::InherentImpl => {
+ let self_ty = tcx.type_of(def_id);
+ inputs.extend(self_ty.walk());
+ }
+
+ // In an fn, we assume that the arguments and all their constituents are
+ // well-formed.
+ NodeKind::Fn => {
+ let fn_sig = tcx.fn_sig(def_id);
+ let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
+
+ inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
+ }
+
+ NodeKind::Other => (),
+ }
+ let input_clauses = inputs.into_iter().filter_map(|arg| {
+ match arg.unpack() {
+ GenericArgKind::Type(ty) => {
+ let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty));
+ Some(tcx.mk_predicate(PredicateKind::ForAll(binder)))
+ }
+
+ // FIXME(eddyb) no WF conditions from lifetimes?
+ GenericArgKind::Lifetime(_) => None,
+
+ // FIXME(eddyb) support const generics in Chalk
+ GenericArgKind::Const(_) => None,
+ }
+ });
+
+ tcx.mk_predicates(clauses.chain(input_clauses))
+}
+
+fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
+ tcx.param_env(def_id).with_reveal_all_normalized(tcx)
+}
+
+fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
+ assert_eq!(crate_num, LOCAL_CRATE);
+ tcx.sess.local_crate_disambiguator()
+}
+
+fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
+ assert_eq!(crate_num, LOCAL_CRATE);
+ tcx.crate_name
+}
+
+fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
+ tcx.index_hir(crate_num).crate_hash
+}
+
+fn instance_def_size_estimate<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance_def: ty::InstanceDef<'tcx>,
+) -> usize {
+ use ty::InstanceDef;
+
+ match instance_def {
+ InstanceDef::Item(..) | InstanceDef::DropGlue(..) => {
+ let mir = tcx.instance_mir(instance_def);
+ mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum()
+ }
+ // Estimate the size of other compiler-generated shims to be 1.
+ _ => 1,
+ }
+}
+
+/// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`.
+///
+/// See [`ty::ImplOverlapKind::Issue33140`] for more details.
+fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
+ debug!("issue33140_self_ty({:?})", def_id);
+
+ let trait_ref = tcx
+ .impl_trait_ref(def_id)
+ .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));
+
+ debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
+
+ let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive
+ && tcx.associated_item_def_ids(trait_ref.def_id).is_empty();
+
+ // Check whether these impls would be ok for a marker trait.
+ if !is_marker_like {
+ debug!("issue33140_self_ty - not marker-like!");
+ return None;
+ }
+
+ // impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
+ if trait_ref.substs.len() != 1 {
+ debug!("issue33140_self_ty - impl has substs!");
+ return None;
+ }
+
+ let predicates = tcx.predicates_of(def_id);
+ if predicates.parent.is_some() || !predicates.predicates.is_empty() {
+ debug!("issue33140_self_ty - impl has predicates {:?}!", predicates);
+ return None;
+ }
+
+ let self_ty = trait_ref.self_ty();
+ let self_ty_matches = match self_ty.kind() {
+ ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
+ _ => false,
+ };
+
+ if self_ty_matches {
+ debug!("issue33140_self_ty - MATCHES!");
+ Some(self_ty)
+ } else {
+ debug!("issue33140_self_ty - non-matching self type");
+ None
+ }
+}
+
+/// Check if a function is async.
+fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+
+ let node = tcx.hir().get(hir_id);
+
+ let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
+ bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
+ });
+
+ fn_like.asyncness()
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers {
+ asyncness,
+ associated_item,
+ associated_item_def_ids,
+ associated_items,
+ adt_sized_constraint,
+ def_span,
+ param_env,
+ param_env_reveal_all_normalized,
+ trait_of_item,
+ crate_disambiguator,
+ original_crate_name,
+ crate_hash,
+ instance_def_size_estimate,
+ issue33140_self_ty,
+ impl_defaultness,
+ ..*providers
+ };
+}
use crate::astconv::AstConv;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty;
use rustc_session::parse::feature_err;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
.collect();
if let (Some(suggested_name), true) = (
- find_best_match_for_name(all_candidate_names.iter(), assoc_name.name, None),
+ find_best_match_for_name(&all_candidate_names, assoc_name.name, None),
assoc_name.span != DUMMY_SP,
) {
err.span_suggestion(
};
use crate::middle::resolve_lifetime as rl;
use crate::require_c_abi_if_c_variadic;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError};
use rustc_hir as hir;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi;
infer_args,
);
+ // Skip processing if type has no generic parameters.
+ // Traits always have `Self` as a generic parameter, which means they will not return early
+ // here and so associated type bindings will be handled regardless of whether there are any
+ // non-`Self` generic parameters.
+ if generic_params.params.len() == 0 {
+ return (tcx.intern_substs(&[]), vec![], arg_count);
+ }
+
let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
struct SubstsForAstPathCtxt<'a, 'tcx> {
|| {
traits::transitive_bounds(
tcx,
- predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()),
+ predicates.iter().filter_map(|(p, _)| {
+ p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value)
+ }),
)
},
|| param_name.to_string(),
let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
if let Some(suggested_name) = find_best_match_for_name(
- adt_def.variants.iter().map(|variant| &variant.ident.name),
+ &adt_def
+ .variants
+ .iter()
+ .map(|variant| variant.ident.name)
+ .collect::<Vec<Symbol>>(),
assoc_ident.name,
None,
) {
fn_maybe_err(tcx, span, fn_sig.abi);
+ if fn_sig.abi == Abi::RustCall {
+ let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
+
+ let err = || {
+ let item = match tcx.hir().get(fn_id) {
+ Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
+ Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(header, ..), ..
+ }) => Some(header),
+ // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
+ Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => None,
+ node => bug!("Item being checked wasn't a function/closure: {:?}", node),
+ };
+
+ if let Some(header) = item {
+ tcx.sess.span_err(header.span, "A function with the \"rust-call\" ABI must take a single non-self argument that is a tuple")
+ }
+ };
+
+ if fn_sig.inputs().len() != expected_args {
+ err()
+ } else {
+ // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
+ // This will probably require wide-scale changes to support a TupleKind obligation
+ // We can't resolve this without knowing the type of the param
+ if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
+ err()
+ }
+ }
+ }
+
if body.generator_kind.is_some() && can_be_generator.is_some() {
let yield_ty = fcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
struct ProhibitOpaqueVisitor<'tcx> {
opaque_identity_ty: Ty<'tcx>,
generics: &'tcx ty::Generics,
- };
+ }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
type BreakTy = Option<Ty<'tcx>>;
let generics = tcx.generics_of(def_id);
check_type_params_are_used(tcx, &generics, pty_ty);
}
- hir::ItemKind::ForeignMod(ref m) => {
- check_abi(tcx, it.span, m.abi);
+ hir::ItemKind::ForeignMod { abi, items } => {
+ check_abi(tcx, it.span, abi);
- if m.abi == Abi::RustIntrinsic {
- for item in m.items {
+ if abi == Abi::RustIntrinsic {
+ for item in items {
+ let item = tcx.hir().foreign_item(item.id);
intrinsic::check_intrinsic_type(tcx, item);
}
- } else if m.abi == Abi::PlatformIntrinsic {
- for item in m.items {
+ } else if abi == Abi::PlatformIntrinsic {
+ for item in items {
+ let item = tcx.hir().foreign_item(item.id);
intrinsic::check_platform_intrinsic_type(tcx, item);
}
} else {
- for item in m.items {
- let def_id = tcx.hir().local_def_id(item.hir_id);
+ for item in items {
+ let def_id = tcx.hir().local_def_id(item.id.hir_id);
let generics = tcx.generics_of(def_id);
let own_counts = generics.own_counts();
if generics.params.len() - own_counts.lifetimes != 0 {
.emit();
}
+ let item = tcx.hir().foreign_item(item.id);
match item.kind {
hir::ForeignItemKind::Fn(ref fn_decl, _, _) => {
- require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
+ require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
}
hir::ForeignItemKind::Static(..) => {
check_static_inhabited(tcx, def_id, item.span);
// can be given the suggestion "u32::from(x) > y" rather than
// "x > y.try_into().unwrap()".
let lhs_expr_and_src = expected_ty_expr.and_then(|expr| {
- match self.tcx.sess.source_map().span_to_snippet(expr.span).ok() {
- Some(src) => Some((expr, src)),
- None => None,
- }
+ self.tcx
+ .sess
+ .source_map()
+ .span_to_snippet(expr.span)
+ .ok()
+ .map(|src| (expr, src))
});
let (span, msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
(lhs_expr_and_src, exp_to_found_is_fallible)
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use rustc_ast as ast;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{AdtKind, Visibility};
use rustc_span::hygiene::DesugaringKind;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_trait_selection::traits::{self, ObligationCauseCode};
field: Symbol,
skip: Vec<Symbol>,
) -> Option<Symbol> {
- let names = variant.fields.iter().filter_map(|field| {
- // ignore already set fields and private fields from non-local crates
- if skip.iter().any(|&x| x == field.ident.name)
- || (!variant.def_id.is_local() && field.vis != Visibility::Public)
- {
- None
- } else {
- Some(&field.ident.name)
- }
- });
+ let names = variant
+ .fields
+ .iter()
+ .filter_map(|field| {
+ // ignore already set fields and private fields from non-local crates
+ if skip.iter().any(|&x| x == field.ident.name)
+ || (!variant.def_id.is_local() && field.vis != Visibility::Public)
+ {
+ None
+ } else {
+ Some(field.ident.name)
+ }
+ })
+ .collect::<Vec<Symbol>>();
- find_best_match_for_name(names, field, None)
+ find_best_match_for_name(&names, field, None)
}
fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<Symbol> {
use crate::hir::def_id::DefId;
use rustc_ast as ast;
-use rustc_ast::util::lev_distance::{find_best_match_for_name, lev_distance};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
+use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
use rustc_trait_selection::autoderef::{self, Autoderef};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
Ok(None)
} else {
let best_name = {
- let names = applicable_close_candidates.iter().map(|cand| &cand.ident.name);
- find_best_match_for_name(names, self.method_name.unwrap().name, None)
+ let names = applicable_close_candidates
+ .iter()
+ .map(|cand| cand.ident.name)
+ .collect::<Vec<Symbol>>();
+ find_best_match_for_name(&names, self.method_name.unwrap().name, None)
}
.unwrap();
Ok(applicable_close_candidates
//! found or is otherwise invalid.
use crate::check::FnCtxt;
-use rustc_ast::util::lev_distance;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_middle::ty::{
self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
+use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{source_map, FileName, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
if actual.is_enum() {
let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = lev_distance::find_best_match_for_name(
- adt_def.variants.iter().map(|s| &s.ident.name),
+ &adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(),
item_name.name,
None,
) {
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::Visitor;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{HirIdMap, Node};
+use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
}
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
+ fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
}
fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
use crate::check::FnCtxt;
use rustc_ast as ast;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_middle::ty::subst::GenericArg;
use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
use rustc_span::hygiene::DesugaringKind;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Ident;
use rustc_trait_selection::traits::{ObligationCause, Pattern};
),
);
if plural == "" {
- let input = unmentioned_fields.iter().map(|(_, field)| &field.name);
- let suggested_name = find_best_match_for_name(input, ident.name, None);
+ let input =
+ unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>();
+ let suggested_name = find_best_match_for_name(&input, ident.name, None);
if let Some(suggested_name) = suggested_name {
err.span_suggestion(
ident.span,
hir::ItemKind::Const(ref ty, ..) => {
check_item_type(tcx, item.hir_id, ty.span, false);
}
- hir::ItemKind::ForeignMod(ref module) => {
- for it in module.items.iter() {
+ hir::ItemKind::ForeignMod { items, .. } => {
+ for it in items.iter() {
+ let it = tcx.hir().foreign_item(it.id);
match it.kind {
hir::ForeignItemKind::Fn(ref decl, ..) => {
check_item_fn(tcx, it.hir_id, it.ident, it.span, decl)
),
)
.note("the only supported types are integers, `bool` and `char`")
- .note("more complex types are supported with `#[feature(const_generics)]`")
+ .help("more complex types are supported with `#[feature(const_generics)]`")
.emit()
}
};
fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
Visitor::visit_impl_item(&mut self.clone(), impl_item);
}
+
+ fn visit_foreign_item(&self, foreign_item: &'tcx hir::ForeignItem<'tcx>) {
+ Visitor::visit_foreign_item(&mut self.clone(), foreign_item)
+ }
}
impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
let mut typeck_results = self.fcx.typeck_results.borrow_mut();
// All valid indexing looks like this; might encounter non-valid indexes at this point.
- let base_ty = typeck_results.expr_ty_adjusted_opt(&base).map(|t| t.kind());
+ let base_ty = typeck_results
+ .expr_ty_adjusted_opt(&base)
+ .map(|t| self.fcx.resolve_vars_if_possible(t).kind());
if base_ty.is_none() {
// When encountering `return [0][0]` outside of a `fn` body we can encounter a base
// that isn't in the type table. We assume more relevant errors have already been
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
struct CheckVisitor<'tcx> {
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
impl InherentCollect<'tcx> {
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'v>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'v>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'v>) {}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
| hir::ItemKind::Use(..)
| hir::ItemKind::Mod(_)
| hir::ItemKind::GlobalAsm(_) => {}
- hir::ItemKind::ForeignMod(ref foreign_mod) => {
- for item in foreign_mod.items {
+ hir::ItemKind::ForeignMod { items, .. } => {
+ for item in items {
+ let item = tcx.hir().foreign_item(item.id);
let def_id = tcx.hir().local_def_id(item.hir_id);
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Mod(..)
- | ItemKind::ForeignMod(..)
+ | ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {}
}
fn enforce_impl_params_are_constrained(
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {}
+
+ fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {}
}
fn insert_required_predicates_to_be_wf<'tcx>(
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
+ fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
}
self.visit_node_helper(item.hir_id);
}
- hir::ItemKind::ForeignMod(ref foreign_mod) => {
- for foreign_item in foreign_mod.items {
- if let hir::ForeignItemKind::Fn(..) = foreign_item.kind {
- self.visit_node_helper(foreign_item.hir_id);
- }
- }
- }
-
_ => {}
}
}
self.visit_node_helper(impl_item.hir_id);
}
}
+
+ fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
+ if let hir::ForeignItemKind::Fn(..) = foreign_item.kind {
+ self.visit_node_helper(foreign_item.hir_id);
+ }
+ }
}
impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_inferreds_for_item(item.hir_id);
}
- hir::ItemKind::ForeignMod(ref foreign_mod) => {
- for foreign_item in foreign_mod.items {
- if let hir::ForeignItemKind::Fn(..) = foreign_item.kind {
- self.add_inferreds_for_item(foreign_item.hir_id);
- }
- }
- }
-
_ => {}
}
}
self.add_inferreds_for_item(impl_item.hir_id);
}
}
+
+ fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
+ if let hir::ForeignItemKind::Fn(..) = foreign_item.kind {
+ self.add_inferreds_for_item(foreign_item.hir_id);
+ }
+ }
}
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
+ fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
}
# nightly features
#channel = "dev"
+# A descriptive string to be appended to `rustc --version` output, which is
+# also used in places like debuginfo `DW_AT_producer`. This may be useful for
+# supplementary build information, like distro-specific package versions.
+#description = ""
+
# The root location of the musl installation directory.
#musl-root = "..."
/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
#[stable(feature = "global_alloc", since = "1.28.0")]
-#[cfg(not(any(test, bootstrap)))]
+#[cfg(not(test))]
#[rustc_allocator_nounwind]
+#[cold]
pub fn handle_alloc_error(layout: Layout) -> ! {
unsafe {
__rust_alloc_error_handler(layout.size(), layout.align());
#[cfg(test)]
pub use std::alloc::handle_alloc_error;
-// In stage0 (bootstrap) `__rust_alloc_error_handler`,
-// might not be generated yet, because an old compiler is used,
-// so use the old direct call.
-#[cfg(all(bootstrap, not(test)))]
-#[stable(feature = "global_alloc", since = "1.28.0")]
-#[doc(hidden)]
-#[rustc_allocator_nounwind]
-pub fn handle_alloc_error(layout: Layout) -> ! {
- extern "Rust" {
- #[lang = "oom"]
- fn oom_impl(layout: Layout) -> !;
- }
- unsafe { oom_impl(layout) }
-}
-
-#[cfg(not(any(target_os = "hermit", test, bootstrap)))]
+#[cfg(not(any(target_os = "hermit", test)))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
//! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
//! [`Global`] allocator with [`Layout::for_value(&*value)`].
//!
+//! For zero-sized values, the `Box` pointer still has to be [valid] for reads
+//! and writes and sufficiently aligned. In particular, casting any aligned
+//! non-zero integer literal to a raw pointer produces a valid pointer, but a
+//! pointer pointing into previously allocated memory that since got freed is
+//! not valid. The recommended way to build a Box to a ZST if `Box::new` cannot
+//! be used is to use [`ptr::NonNull::dangling`].
+//!
//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented
//! as a single pointer and is also ABI-compatible with C pointers
//! (i.e. the C type `T*`). This means that if you have extern "C"
//! [`Global`]: crate::alloc::Global
//! [`Layout`]: crate::alloc::Layout
//! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value
+//! [valid]: ptr#safety
#![stable(feature = "rust1", since = "1.0.0")]
/// memory problems. For example, a double-free may occur if the
/// function is called twice on the same raw pointer.
///
+ /// The safety conditions are described in the [memory layout] section.
+ ///
/// # Examples
+ ///
/// Recreate a `Box` which was previously converted to a raw pointer
/// using [`Box::into_raw`]:
/// ```
}
#[stable(feature = "box_slice_clone", since = "1.3.0")]
-impl<T: Clone> Clone for Box<[T]> {
+impl<T: Clone, A: AllocRef + Clone> Clone for Box<[T], A> {
fn clone(&self) -> Self {
- self.to_vec().into_boxed_slice()
+ let alloc = Box::alloc_ref(self).clone();
+ self.to_vec_in(alloc).into_boxed_slice()
}
fn clone_from(&mut self, other: &Self) {
where
I: Iterator<Item = (K, V)>,
{
- let mut cur_node = self.node_as_mut().last_leaf_edge().into_node();
+ let mut cur_node = self.borrow_mut().last_leaf_edge().into_node();
// Iterate through all key-value pairs, pushing them into nodes at the right level.
for (key, value) in iter {
// Try to push key-value pair into the current leaf node.
// Push key-value pair and new right subtree.
let tree_height = open_node.height() - 1;
- let mut right_tree = Root::new_leaf();
+ let mut right_tree = Root::new();
for _ in 0..tree_height {
right_tree.push_internal_level();
}
fn fix_right_edge(&mut self) {
// Handle underfull nodes, start from the top.
- let mut cur_node = self.node_as_mut();
+ 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();
use core::ptr;
use super::borrow::DormantMutRef;
-use super::node::{self, marker, ForceResult::*, Handle, NodeRef};
+use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
use super::search::{self, SearchResult::*};
use super::unwrap_unchecked;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BTreeMap<K, V> {
- root: Option<node::Root<K, V>>,
+ root: Option<Root<K, V>>,
length: usize,
}
impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
fn clone(&self) -> BTreeMap<K, V> {
fn clone_subtree<'a, K: Clone, V: Clone>(
- node: node::NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>,
+ node: NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>,
) -> BTreeMap<K, V>
where
K: 'a,
{
match node.force() {
Leaf(leaf) => {
- let mut out_tree = BTreeMap { root: Some(node::Root::new_leaf()), length: 0 };
+ let mut out_tree = BTreeMap { root: Some(Root::new()), length: 0 };
{
let root = out_tree.root.as_mut().unwrap(); // unwrap succeeds because we just wrapped
- let mut out_node = match root.node_as_mut().force() {
+ let mut out_node = match root.borrow_mut().force() {
Leaf(leaf) => leaf,
Internal(_) => unreachable!(),
};
(root, length)
};
- out_node.push(k, v, subroot.unwrap_or_else(node::Root::new_leaf));
+ out_node.push(k, v, subroot.unwrap_or_else(Root::new));
out_tree.length += 1 + sublength;
}
}
// Ord` constraint, which this method lacks.
BTreeMap { root: None, length: 0 }
} else {
- clone_subtree(self.root.as_ref().unwrap().node_as_ref()) // unwrap succeeds because not empty
+ clone_subtree(self.root.as_ref().unwrap().reborrow()) // unwrap succeeds because not empty
}
}
}
type Key = K;
fn get(&self, key: &Q) -> Option<&K> {
- let root_node = self.root.as_ref()?.node_as_ref();
+ let root_node = self.root.as_ref()?.reborrow();
match search::search_tree(root_node, key) {
Found(handle) => Some(handle.into_kv().0),
GoDown(_) => None,
fn take(&mut self, key: &Q) -> Option<K> {
let (map, dormant_map) = DormantMutRef::new(self);
- let root_node = map.root.as_mut()?.node_as_mut();
+ let root_node = map.root.as_mut()?.borrow_mut();
match search::search_tree(root_node, key) {
Found(handle) => {
Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_kv().0)
fn replace(&mut self, key: K) -> Option<K> {
let (map, dormant_map) = DormantMutRef::new(self);
- let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut();
+ 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)),
GoDown(handle) => {
}
impl<K: Ord, V> BTreeMap<K, V> {
- /// Makes a new empty BTreeMap.
+ /// Makes a new, empty `BTreeMap`.
///
/// Does not allocate anything on its own.
///
K: Borrow<Q>,
Q: Ord,
{
- let root_node = self.root.as_ref()?.node_as_ref();
+ let root_node = self.root.as_ref()?.reborrow();
match search::search_tree(root_node, key) {
Found(handle) => Some(handle.into_kv().1),
GoDown(_) => None,
K: Borrow<Q>,
Q: Ord,
{
- let root_node = self.root.as_ref()?.node_as_ref();
+ let root_node = self.root.as_ref()?.reborrow();
match search::search_tree(root_node, k) {
Found(handle) => Some(handle.into_kv()),
GoDown(_) => None,
/// ```
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn first_key_value(&self) -> Option<(&K, &V)> {
- let root_node = self.root.as_ref()?.node_as_ref();
+ let root_node = self.root.as_ref()?.reborrow();
root_node.first_leaf_edge().right_kv().ok().map(Handle::into_kv)
}
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
let (map, dormant_map) = DormantMutRef::new(self);
- let root_node = map.root.as_mut()?.node_as_mut();
+ let root_node = map.root.as_mut()?.borrow_mut();
let kv = root_node.first_leaf_edge().right_kv().ok()?;
Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData })
}
/// ```
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn last_key_value(&self) -> Option<(&K, &V)> {
- let root_node = self.root.as_ref()?.node_as_ref();
+ let root_node = self.root.as_ref()?.reborrow();
root_node.last_leaf_edge().left_kv().ok().map(Handle::into_kv)
}
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
let (map, dormant_map) = DormantMutRef::new(self);
- let root_node = map.root.as_mut()?.node_as_mut();
+ let root_node = map.root.as_mut()?.borrow_mut();
let kv = root_node.last_leaf_edge().left_kv().ok()?;
Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData })
}
K: Borrow<Q>,
Q: Ord,
{
- let root_node = self.root.as_mut()?.node_as_mut();
+ let root_node = self.root.as_mut()?.borrow_mut();
match search::search_tree(root_node, key) {
Found(handle) => Some(handle.into_val_mut()),
GoDown(_) => None,
Q: Ord,
{
let (map, dormant_map) = DormantMutRef::new(self);
- let root_node = map.root.as_mut()?.node_as_mut();
+ let root_node = map.root.as_mut()?.borrow_mut();
match search::search_tree(root_node, key) {
Found(handle) => {
Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_entry())
R: RangeBounds<T>,
{
if let Some(root) = &self.root {
- let (f, b) = root.node_as_ref().range_search(range);
+ let (f, b) = root.reborrow().range_search(range);
Range { front: Some(f), back: Some(b) }
} else {
R: RangeBounds<T>,
{
if let Some(root) = &mut self.root {
- let (f, b) = root.node_as_valmut().range_search(range);
+ let (f, b) = root.borrow_valmut().range_search(range);
RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }
} else {
/// let mut count: BTreeMap<&str, usize> = BTreeMap::new();
///
/// // count the number of occurrences of letters in the vec
- /// for x in vec!["a","b","a","c","a","b"] {
+ /// for x in vec!["a", "b", "a", "c", "a", "b"] {
/// *count.entry(x).or_insert(0) += 1;
/// }
///
pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
// FIXME(@porglezomp) Avoid allocating if we don't insert
let (map, dormant_map) = DormantMutRef::new(self);
- let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut();
+ let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut();
match search::search_tree(root_node, &key) {
Found(handle) => Occupied(OccupiedEntry { handle, dormant_map, _marker: PhantomData }),
GoDown(handle) => {
left_root.split_off(right_root, key);
if left_root.height() < right_root.height() {
- self.length = left_root.node_as_ref().calc_length();
+ self.length = left_root.reborrow().calc_length();
right.length = total_num - self.len();
} else {
- right.length = right_root.node_as_ref().calc_length();
+ right.length = right_root.reborrow().calc_length();
self.length = total_num - right.len();
}
pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V> {
if let Some(root) = self.root.as_mut() {
let (root, dormant_root) = DormantMutRef::new(root);
- let front = root.node_as_mut().first_leaf_edge();
+ let front = root.borrow_mut().first_leaf_edge();
DrainFilterInner {
length: &mut self.length,
dormant_root: Some(dormant_root),
fn into_iter(self) -> IntoIter<K, V> {
let mut me = ManuallyDrop::new(self);
if let Some(root) = me.root.take() {
- let (f, b) = root.into_ref().full_range();
+ let (f, b) = root.full_range();
IntoIter { front: Some(f), back: Some(b), length: me.length }
} else {
pred: F,
inner: DrainFilterInner<'a, K, V>,
}
-/// Most of the implementation of DrainFilter, independent of the type
+/// Most of the implementation of DrainFilter are generic over the type
/// of the predicate, thus also serving for BTreeSet::DrainFilter.
pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> {
/// Reference to the length field in the borrowed map, updated live.
length: &'a mut usize,
- /// Burried reference to the root field in the borrowed map.
+ /// Buried reference to the root field in the borrowed map.
/// Wrapped in `Option` to allow drop handler to `take` it.
- dormant_root: Option<DormantMutRef<'a, node::Root<K, V>>>,
+ dormant_root: Option<DormantMutRef<'a, Root<K, V>>>,
/// Contains a leaf edge preceding the next element to be returned, or the last leaf edge.
/// Empty if the map has no root, if iteration went beyond the last leaf edge,
/// or if a panic occurred in the predicate.
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Ord, V> Default for BTreeMap<K, V> {
- /// Creates an empty `BTreeMap<K, V>`.
+ /// Creates an empty `BTreeMap`.
fn default() -> BTreeMap<K, V> {
BTreeMap::new()
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<'_, K, V> {
if let Some(root) = &self.root {
- let (f, b) = root.node_as_ref().full_range();
+ let (f, b) = root.reborrow().full_range();
Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length }
} else {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
if let Some(root) = &mut self.root {
- let (f, b) = root.node_as_valmut().full_range();
+ let (f, b) = root.borrow_valmut().full_range();
IterMut {
range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData },
/// If the root node is the empty (non-allocated) root node, allocate our
/// own node. Is an associated function to avoid borrowing the entire BTreeMap.
- fn ensure_is_owned(root: &mut Option<node::Root<K, V>>) -> &mut node::Root<K, V> {
- root.get_or_insert_with(node::Root::new_leaf)
+ fn ensure_is_owned(root: &mut Option<Root<K, V>>) -> &mut Root<K, V> {
+ root.get_or_insert_with(Root::new)
}
}
// Safety: We have consumed self.handle and the reference returned.
let map = unsafe { self.dormant_map.awaken() };
let root = map.root.as_mut().unwrap();
- root.push_internal_level().push(ins.k, ins.v, ins.right);
+ root.push_internal_level().push(ins.kv.0, ins.kv.1, ins.right);
map.length += 1;
val_ptr
}
use crate::rc::Rc;
use crate::string::{String, ToString};
use crate::vec::Vec;
+use std::cmp::Ordering;
use std::convert::TryFrom;
use std::iter::{self, FromIterator};
use std::mem;
use std::ops::Bound::{self, Excluded, Included, Unbounded};
use std::ops::RangeBounds;
use std::panic::{catch_unwind, AssertUnwindSafe};
-use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
mod ord_chaos;
use ord_chaos::{Cyclic3, Governed, Governor};
// Panics if the map (or the code navigating it) is corrupted.
fn check_invariants(&self) {
if let Some(root) = &self.root {
- let root_node = root.node_as_ref();
+ let root_node = root.reborrow();
// Check the back pointers top-down, before we attempt to rely on
// more serious navigation code.
assert!(root_node.ascend().is_err());
root_node.assert_back_pointers();
- // Check consistenty of `length` and some of the navigation.
+ // Check consistency of `length` with what navigation code encounters.
assert_eq!(self.length, root_node.calc_length());
- assert_eq!(self.length, self.keys().count());
// Lastly, check the invariant causing the least harm.
root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 });
} else {
- // Check consistenty of `length` and some of the navigation.
assert_eq!(self.length, 0);
- assert_eq!(self.length, self.keys().count());
}
+
+ // Check that `assert_strictly_ascending` will encounter all keys.
+ assert_eq!(self.length, self.keys().count());
}
// Panics if the map is corrupted or if the keys are not in strictly
// ascending order, in the current opinion of the `Ord` implementation.
- // If the `Ord` implementation does not honor transitivity, this method
- // does not guarantee that all the keys are unique, just that adjacent
- // keys are unique.
+ // If the `Ord` implementation violates transitivity, this method does not
+ // guarantee that all keys are unique, just that adjacent keys are unique.
fn check(&self)
where
K: Debug + Ord,
K: Debug,
{
if let Some(root) = self.root.as_ref() {
- root.node_as_ref().dump_keys()
+ root.reborrow().dump_keys()
} else {
String::from("not yet allocated")
}
map.check();
}
+ // Explicitly consumes the iterator, where most test cases drop it instantly.
#[test]
fn consumed_keeping_all() {
let pairs = (0..3).map(|i| (i, i));
map.check();
}
+ // Explicitly consumes the iterator, where most test cases drop it instantly.
#[test]
fn consumed_removing_all() {
let pairs = (0..3).map(|i| (i, i));
map.check();
}
- #[test]
- fn dropped_removing_all() {
- let pairs = (0..3).map(|i| (i, i));
- let mut map: BTreeMap<_, _> = pairs.collect();
- map.drain_filter(|_, _| true);
- assert!(map.is_empty());
- map.check();
- }
-
+ // Explicitly consumes the iterator and modifies values through it.
#[test]
fn mutating_and_keeping() {
let pairs = (0..3).map(|i| (i, i));
map.check();
}
+ // Explicitly consumes the iterator and modifies values through it.
#[test]
fn mutating_and_removing() {
let pairs = (0..3).map(|i| (i, i));
struct D;
impl Drop for D {
fn drop(&mut self) {
- if DROPS.fetch_add(1, Ordering::SeqCst) == 1 {
+ if DROPS.fetch_add(1, SeqCst) == 1 {
panic!("panic in `drop`");
}
}
catch_unwind(move || {
drop(map.drain_filter(|i, _| {
- PREDS.fetch_add(1usize << i, Ordering::SeqCst);
+ PREDS.fetch_add(1usize << i, SeqCst);
true
}))
})
.unwrap_err();
- assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
- assert_eq!(DROPS.load(Ordering::SeqCst), 3);
+ assert_eq!(PREDS.load(SeqCst), 0x011);
+ assert_eq!(DROPS.load(SeqCst), 3);
}
#[test]
struct D;
impl Drop for D {
fn drop(&mut self) {
- DROPS.fetch_add(1, Ordering::SeqCst);
+ DROPS.fetch_add(1, SeqCst);
}
}
catch_unwind(AssertUnwindSafe(|| {
drop(map.drain_filter(|i, _| {
- PREDS.fetch_add(1usize << i, Ordering::SeqCst);
+ PREDS.fetch_add(1usize << i, SeqCst);
match i {
0 => true,
_ => panic!(),
}))
.unwrap_err();
- assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
- assert_eq!(DROPS.load(Ordering::SeqCst), 1);
+ assert_eq!(PREDS.load(SeqCst), 0x011);
+ assert_eq!(DROPS.load(SeqCst), 1);
assert_eq!(map.len(), 2);
assert_eq!(map.first_entry().unwrap().key(), &4);
assert_eq!(map.last_entry().unwrap().key(), &8);
struct D;
impl Drop for D {
fn drop(&mut self) {
- DROPS.fetch_add(1, Ordering::SeqCst);
+ DROPS.fetch_add(1, SeqCst);
}
}
{
let mut it = map.drain_filter(|i, _| {
- PREDS.fetch_add(1usize << i, Ordering::SeqCst);
+ PREDS.fetch_add(1usize << i, SeqCst);
match i {
0 => true,
_ => panic!(),
assert!(matches!(result, Ok(None)));
}
- assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
- assert_eq!(DROPS.load(Ordering::SeqCst), 1);
+ assert_eq!(PREDS.load(SeqCst), 0x011);
+ assert_eq!(DROPS.load(SeqCst), 1);
assert_eq!(map.len(), 2);
assert_eq!(map.first_entry().unwrap().key(), &4);
assert_eq!(map.last_entry().unwrap().key(), &8);
// undefined.
#[test]
fn test_bad_zst() {
- use std::cmp::Ordering;
-
#[derive(Clone, Copy, Debug)]
struct Bad;
impl Drop for D {
fn drop(&mut self) {
- if DROPS.fetch_add(1, Ordering::SeqCst) == 0 {
+ if DROPS.fetch_add(1, SeqCst) == 0 {
panic!("panic in `drop`");
}
}
catch_unwind(move || left.append(&mut right)).unwrap_err();
- assert_eq!(DROPS.load(Ordering::SeqCst), 4); // Rust issue #47949 ate one little piggy
+ assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy
}
#[test]
impl Drop for D {
fn drop(&mut self) {
- if DROPS.fetch_add(1, Ordering::SeqCst) == 3 {
+ if DROPS.fetch_add(1, SeqCst) == 3 {
panic!("panic in `drop`");
}
}
catch_unwind(move || drop(map.into_iter())).unwrap_err();
- assert_eq!(DROPS.load(Ordering::SeqCst), 5);
+ assert_eq!(DROPS.load(SeqCst), 5);
}
#[test]
struct D;
impl Drop for D {
fn drop(&mut self) {
- if DROPS.fetch_add(1, Ordering::SeqCst) == PANIC_POINT.load(Ordering::SeqCst) {
+ if DROPS.fetch_add(1, SeqCst) == PANIC_POINT.load(SeqCst) {
panic!("panic in `drop`");
}
}
}
for panic_point in vec![0, 1, size - 2, size - 1] {
- DROPS.store(0, Ordering::SeqCst);
- PANIC_POINT.store(panic_point, Ordering::SeqCst);
+ DROPS.store(0, SeqCst);
+ PANIC_POINT.store(panic_point, SeqCst);
let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
catch_unwind(move || drop(map.into_iter())).unwrap_err();
- assert_eq!(DROPS.load(Ordering::SeqCst), size);
+ assert_eq!(DROPS.load(SeqCst), size);
}
}
use std::cmp::Ordering::{self, *};
use std::ptr;
+// Minimal type with an `Ord` implementation violating transitivity.
#[derive(Debug)]
pub enum Cyclic3 {
A,
impl Eq for Cyclic3 {}
+// Controls the ordering of values wrapped by `Governed`.
#[derive(Debug)]
pub struct Governor {
flipped: Cell<bool>,
}
}
+// Type with an `Ord` implementation that forms a total order at any moment
+// (assuming that `T` respects total order), but can suddenly be made to invert
+// that total order.
#[derive(Debug)]
pub struct Governed<'a, T>(pub T, pub &'a Governor);
use core::cmp::Ordering;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
-use core::ptr::{self, NonNull, Unique};
+use core::ptr::{self, NonNull};
use crate::alloc::{AllocRef, Global, Layout};
use crate::boxed::Box;
///
/// However, `BoxedNode` contains no information as to which of the two types
/// of nodes it actually contains, and, partially due to this lack of information,
-/// has no destructor.
-struct BoxedNode<K, V> {
- ptr: Unique<LeafNode<K, V>>,
-}
-
-impl<K, V> BoxedNode<K, V> {
- fn from_leaf(node: Box<LeafNode<K, V>>) -> Self {
- BoxedNode { ptr: Unique::from(Box::leak(node)) }
- }
-
- fn from_internal(node: Box<InternalNode<K, V>>) -> Self {
- BoxedNode { ptr: Unique::from(Box::leak(node)).cast() }
- }
-
- fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
- NonNull::from(self.ptr)
- }
-}
+/// is not a separate type and has no destructor.
+type BoxedNode<K, V> = NonNull<LeafNode<K, V>>;
/// An owned tree.
///
/// Note that this does not have a destructor, and must be cleaned up manually.
-pub struct Root<K, V> {
- node: BoxedNode<K, V>,
- /// The number of levels below the root node.
- height: usize,
-}
-
-unsafe impl<K: Sync, V: Sync> Sync for Root<K, V> {}
-unsafe impl<K: Send, V: Send> Send for Root<K, V> {}
+pub type Root<K, V> = NodeRef<marker::Owned, K, V, marker::LeafOrInternal>;
impl<K, V> Root<K, V> {
- /// Returns the number of levels below the root.
- pub fn height(&self) -> usize {
- self.height
- }
-
/// Returns a new owned tree, with its own root node that is initially empty.
- pub fn new_leaf() -> Self {
- Root { node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), height: 0 }
+ pub fn new() -> Self {
+ NodeRef::new_leaf().forget_type()
}
+}
- /// Borrows and returns an immutable reference to the node owned by the root.
- pub fn node_as_ref(&self) -> NodeRef<marker::Immut<'_>, K, V, marker::LeafOrInternal> {
- NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
+ fn new_leaf() -> Self {
+ Self::from_new_leaf(Box::new(unsafe { LeafNode::new() }))
}
- /// Borrows and returns a mutable reference to the node owned by the root.
- pub fn node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::LeafOrInternal> {
- NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
- }
-
- /// Borrows and returns a mutable reference to the leaf node owned by the root.
- /// # Safety
- /// The root node is a leaf.
- unsafe fn leaf_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Leaf> {
- debug_assert!(self.height == 0);
- NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
- }
-
- /// Borrows and returns a mutable reference to the internal node owned by the root.
- /// # Safety
- /// The root node is not a leaf.
- unsafe fn internal_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
- debug_assert!(self.height > 0);
- NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+ fn from_new_leaf(leaf: Box<LeafNode<K, V>>) -> Self {
+ NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
}
+}
- pub fn node_as_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, marker::LeafOrInternal> {
- NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
+ fn from_new_internal(internal: Box<InternalNode<K, V>>, height: usize) -> Self {
+ NodeRef { height, node: NonNull::from(Box::leak(internal)).cast(), _marker: PhantomData }
}
+}
- pub fn into_ref(self) -> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
- NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
+ /// Mutably borrows the owned node. Unlike `reborrow_mut`, this is safe,
+ /// because the return value cannot be used to destroy the node itself,
+ /// and there cannot be other references to the tree (except during the
+ /// process of `into_iter` or `drop`, but that is a horrific already).
+ pub fn borrow_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, Type> {
+ NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
- /// Packs the reference, aware of type and height, into a type-agnostic pointer.
- fn into_boxed_node(self) -> BoxedNode<K, V> {
- self.node
+ /// Slightly mutably borrows the owned node.
+ pub fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
+ NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
+}
+impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
/// Adds a new internal node with a single edge pointing to the previous root node,
/// make that new node the root node, and return it. This increases the height by 1
/// and is the opposite of `pop_internal_level`.
pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
let mut new_node = Box::new(unsafe { InternalNode::new() });
- new_node.edges[0].write(unsafe { ptr::read(&mut self.node) });
-
- self.node = BoxedNode::from_internal(new_node);
- self.height += 1;
+ new_node.edges[0].write(self.node);
+ let mut new_root = NodeRef::from_new_internal(new_node, self.height + 1);
+ new_root.borrow_mut().first_edge().correct_parent_link();
+ *self = new_root.forget_type();
- unsafe {
- let mut ret = self.internal_node_as_mut();
- ret.reborrow_mut().first_edge().correct_parent_link();
- ret
- }
+ // `self.borrow_mut()`, except that we just forgot we're internal now:
+ NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
/// Removes the internal root node, using its first child as the new root node.
/// This decreases the height by 1 and is the opposite of `push_internal_level`.
///
/// Requires exclusive access to the `Root` object but not to the root node;
- /// it will not invalidate existing handles or references to the root node.
+ /// it will not invalidate other handles or references to the root node.
///
/// Panics if there is no internal level, i.e., if the root node is a leaf.
pub fn pop_internal_level(&mut self) {
assert!(self.height > 0);
- let top = BoxedNode::as_ptr(&self.node);
+ let top = self.node;
- let mut internal_node = unsafe { self.internal_node_as_mut() };
- let internal_node = NodeRef::as_internal_mut(&mut internal_node);
- self.node = unsafe { internal_node.edges[0].assume_init_read() };
- self.height -= 1;
- self.node_as_mut().clear_parent_link();
+ let internal_node = NodeRef { height: self.height, node: top, _marker: PhantomData };
+ *self = internal_node.first_edge().descend();
+ self.borrow_mut().clear_parent_link();
unsafe {
Global.dealloc(top.cast(), Layout::new::<InternalNode<K, V>>());
unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::ValMut<'a>, K, V, Type> {}
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type> {}
-impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
- /// Unpack a node reference that was packed by `Root::into_boxed_node`.
- fn from_boxed_node(boxed_node: BoxedNode<K, V>, height: usize) -> Self {
- NodeRef { height, node: boxed_node.as_ptr(), _marker: PhantomData }
- }
-}
-
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
/// Unpack a node reference that was packed as `NodeRef::parent`.
fn from_internal(node: NonNull<InternalNode<K, V>>, height: usize) -> Self {
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.into_boxed_node());
+ self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node);
Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
}
}
*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.into_boxed_node());
+ slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node);
}
self.correct_all_childrens_parent_links();
let edge = match self.reborrow_mut().force() {
ForceResult::Leaf(_) => None,
ForceResult::Internal(internal) => {
- let boxed_node = ptr::read(internal.reborrow().edge_at(idx + 1));
- let mut edge = Root { node: boxed_node, height: internal.height - 1 };
+ let node = ptr::read(internal.reborrow().edge_at(idx + 1));
+ let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
// In practice, clearing the parent is a waste of time, because we will
// insert the node elsewhere and set its parent link again.
- edge.node_as_mut().clear_parent_link();
+ edge.borrow_mut().clear_parent_link();
Some(edge)
}
};
let edge = match self.reborrow_mut().force() {
ForceResult::Leaf(_) => None,
ForceResult::Internal(mut internal) => {
- let boxed_node =
- slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
- let mut edge = Root { node: boxed_node, height: internal.height - 1 };
+ let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
+ let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
// In practice, clearing the parent is a waste of time, because we will
// insert the node elsewhere and set its parent link again.
- edge.node_as_mut().clear_parent_link();
+ edge.borrow_mut().clear_parent_link();
internal.correct_childrens_parent_links(0..old_len);
} else {
let (middle_kv_idx, insertion) = splitpoint(self.idx);
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
- let (mut left, k, v, mut right) = middle.split();
+ let mut result = middle.split();
let mut insertion_edge = match insertion {
LeftOrRight::Left(insert_idx) => unsafe {
- Handle::new_edge(left.reborrow_mut(), insert_idx)
+ Handle::new_edge(result.left.reborrow_mut(), insert_idx)
},
LeftOrRight::Right(insert_idx) => unsafe {
- Handle::new_edge(right.leaf_node_as_mut(), insert_idx)
+ Handle::new_edge(result.right.borrow_mut(), insert_idx)
},
};
let val_ptr = insertion_edge.insert_fit(key, val);
- (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), val_ptr)
+ (InsertResult::Split(result), val_ptr)
}
}
}
debug_assert!(self.node.len() < CAPACITY);
debug_assert!(edge.height == self.node.height - 1);
- let boxed_node = edge.into_boxed_node();
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, boxed_node);
+ slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node);
self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
}
} else {
let (middle_kv_idx, insertion) = splitpoint(self.idx);
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
- let (mut left, k, v, mut right) = middle.split();
+ let mut result = middle.split();
let mut insertion_edge = match insertion {
LeftOrRight::Left(insert_idx) => unsafe {
- Handle::new_edge(left.reborrow_mut(), insert_idx)
+ Handle::new_edge(result.left.reborrow_mut(), insert_idx)
},
LeftOrRight::Right(insert_idx) => unsafe {
- Handle::new_edge(right.internal_node_as_mut(), insert_idx)
+ Handle::new_edge(result.right.borrow_mut(), insert_idx)
},
};
insertion_edge.insert_fit(key, val, edge);
- InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right })
+ InsertResult::Split(result)
}
}
}
(InsertResult::Fit(handle), ptr) => {
return (InsertResult::Fit(handle.forget_node_type()), ptr);
}
- (InsertResult::Split(split), val_ptr) => (split, val_ptr),
+ (InsertResult::Split(split), val_ptr) => (split.forget_node_type(), val_ptr),
};
loop {
split = match split.left.ascend() {
- Ok(parent) => match parent.insert(split.k, split.v, split.right) {
+ Ok(parent) => match parent.insert(split.kv.0, split.kv.1, split.right) {
InsertResult::Fit(handle) => {
return (InsertResult::Fit(handle.forget_node_type()), val_ptr);
}
- InsertResult::Split(split) => split,
+ InsertResult::Split(split) => split.forget_node_type(),
},
Err(root) => {
return (InsertResult::Split(SplitResult { left: root, ..split }), val_ptr);
// reference (Rust issue #73987) and invalidate any other references
// to or inside the array, should any be around.
let parent_ptr = NodeRef::as_internal_ptr(&self.node);
- let boxed_node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() };
- NodeRef::from_boxed_node(boxed_node, self.node.height - 1)
+ let node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() };
+ NodeRef { node, height: self.node.height - 1, _marker: PhantomData }
}
}
/// - The key and value pointed to by this handle are extracted.
/// - All the key/value pairs to the right of this handle are put into a newly
/// allocated node.
- pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
+ pub fn split(mut self) -> SplitResult<'a, K, V, marker::Leaf> {
unsafe {
let mut new_node = Box::new(LeafNode::new());
- let (k, v) = self.split_leaf_data(&mut new_node);
+ let kv = self.split_leaf_data(&mut new_node);
- let right = Root { node: BoxedNode::from_leaf(new_node), height: 0 };
- (self.node, k, v, right)
+ let right = NodeRef::from_new_leaf(new_node);
+ SplitResult { left: self.node, kv, right }
}
}
/// - The key and value pointed to by this handle are extracted.
/// - All the edges and key/value pairs to the right of this handle are put into
/// a newly allocated node.
- pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Internal>, K, V, Root<K, V>) {
+ 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();
new_node.edges.as_mut_ptr(),
new_len + 1,
);
- let (k, v) = self.split_leaf_data(&mut new_node.data);
+ let kv = self.split_leaf_data(&mut new_node.data);
let height = self.node.height;
- let mut right = Root { node: BoxedNode::from_internal(new_node), height };
+ let mut right = NodeRef::from_new_internal(new_node, height);
- right.internal_node_as_mut().correct_childrens_parent_links(0..=new_len);
+ right.borrow_mut().correct_childrens_parent_links(0..=new_len);
- (self.node, k, v, right)
+ SplitResult { left: self.node, kv, right }
}
}
}
}
/// Result of insertion, when a node needed to expand beyond its capacity.
-/// Does not distinguish between `Leaf` and `Internal` because `Root` doesn't.
-pub struct SplitResult<'a, K, V> {
- // Altered node in existing tree with elements and edges that belong to the left of `k`.
- pub left: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
+pub struct SplitResult<'a, K, V, NodeType> {
+ // Altered node in existing tree with elements and edges that belong to the left of `kv`.
+ pub left: NodeRef<marker::Mut<'a>, K, V, NodeType>,
// Some key and value split off, to be inserted elsewhere.
- pub k: K,
- pub v: V,
- // Owned, unattached, new node with elements and edges that belong to the right of `k`.
- pub right: Root<K, V>,
+ pub kv: (K, V),
+ // Owned, unattached, new node with elements and edges that belong to the right of `kv`.
+ pub right: NodeRef<marker::Owned, K, V, NodeType>,
+}
+
+impl<'a, K, V> SplitResult<'a, K, V, marker::Leaf> {
+ pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> {
+ SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() }
+ }
+}
+
+impl<'a, K, V> SplitResult<'a, K, V, marker::Internal> {
+ pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> {
+ SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() }
+ }
}
-pub enum InsertResult<'a, K, V, Type> {
- Fit(Handle<NodeRef<marker::Mut<'a>, K, V, Type>, marker::KV>),
- Split(SplitResult<'a, K, V>),
+pub enum InsertResult<'a, K, V, NodeType> {
+ Fit(Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV>),
+ Split(SplitResult<'a, K, V, NodeType>),
}
pub mod marker {
#[test]
fn test_partial_cmp_eq() {
- let mut root1: Root<i32, ()> = Root::new_leaf();
- let mut leaf1 = unsafe { root1.leaf_node_as_mut() };
+ let mut root1 = NodeRef::new_leaf();
+ let mut leaf1 = root1.borrow_mut();
leaf1.push(1, ());
+ let mut root1 = root1.forget_type();
root1.push_internal_level();
- let root2: Root<i32, ()> = Root::new_leaf();
+ let root2 = Root::new();
+ root1.reborrow().assert_back_pointers();
+ root2.reborrow().assert_back_pointers();
- let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type();
- let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type();
- let top_edge_1 = root1.node_as_ref().first_edge();
- let top_edge_2 = root2.node_as_ref().first_edge();
+ let leaf_edge_1a = root1.reborrow().first_leaf_edge().forget_node_type();
+ let leaf_edge_1b = root1.reborrow().last_leaf_edge().forget_node_type();
+ let top_edge_1 = root1.reborrow().first_edge();
+ let top_edge_2 = root2.reborrow().first_edge();
assert!(leaf_edge_1a == leaf_edge_1a);
assert!(leaf_edge_1a != leaf_edge_1b);
assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None);
root1.pop_internal_level();
- unsafe { root1.into_ref().deallocate_and_ascend() };
- unsafe { root2.into_ref().deallocate_and_ascend() };
+ unsafe { root1.deallocate_and_ascend() };
+ unsafe { root2.deallocate_and_ascend() };
}
#[test]
{
match search_linear(&node, key) {
(idx, true) => Found(unsafe { Handle::new_kv(node, idx) }),
- (idx, false) => SearchResult::GoDown(unsafe { Handle::new_edge(node, idx) }),
+ (idx, false) => GoDown(unsafe { Handle::new_edge(node, idx) }),
}
}
const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16;
impl<T: Ord> BTreeSet<T> {
- /// Makes a new `BTreeSet` with a reasonable choice of B.
+ /// Makes a new, empty `BTreeSet`.
+ ///
+ /// Does not allocate anything on its own.
///
/// # Examples
///
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Default for BTreeSet<T> {
- /// Makes an empty `BTreeSet<T>` with a reasonable choice of B.
+ /// Creates an empty `BTreeSet`.
fn default() -> BTreeSet<T> {
BTreeSet::new()
}
use super::super::DeterministicRng;
use super::*;
use crate::vec::Vec;
+use std::cmp::Ordering;
use std::iter::FromIterator;
use std::panic::{catch_unwind, AssertUnwindSafe};
-use std::sync::atomic::{AtomicU32, Ordering};
+use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
#[test]
fn test_clone_eq() {
struct D(i32);
impl Drop for D {
fn drop(&mut self) {
- if DROPS.fetch_add(1, Ordering::SeqCst) == 1 {
+ if DROPS.fetch_add(1, SeqCst) == 1 {
panic!("panic in `drop`");
}
}
catch_unwind(move || {
drop(set.drain_filter(|d| {
- PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst);
+ PREDS.fetch_add(1u32 << d.0, SeqCst);
true
}))
})
.ok();
- assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
- assert_eq!(DROPS.load(Ordering::SeqCst), 3);
+ assert_eq!(PREDS.load(SeqCst), 0x011);
+ assert_eq!(DROPS.load(SeqCst), 3);
}
#[test]
struct D(i32);
impl Drop for D {
fn drop(&mut self) {
- DROPS.fetch_add(1, Ordering::SeqCst);
+ DROPS.fetch_add(1, SeqCst);
}
}
catch_unwind(AssertUnwindSafe(|| {
drop(set.drain_filter(|d| {
- PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst);
+ PREDS.fetch_add(1u32 << d.0, SeqCst);
match d.0 {
0 => true,
_ => panic!(),
}))
.ok();
- assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
- assert_eq!(DROPS.load(Ordering::SeqCst), 1);
+ assert_eq!(PREDS.load(SeqCst), 0x011);
+ assert_eq!(DROPS.load(SeqCst), 1);
assert_eq!(set.len(), 2);
assert_eq!(set.first().unwrap().0, 4);
assert_eq!(set.last().unwrap().0, 8);
#[test]
fn test_recovery() {
- use std::cmp::Ordering;
-
#[derive(Debug)]
struct Foo(&'static str, i32);
K: Borrow<Q>,
{
debug_assert!(right_root.height() == 0);
- debug_assert!(right_root.node_as_ref().len() == 0);
+ debug_assert!(right_root.len() == 0);
let left_root = self;
for _ in 0..left_root.height() {
}
{
- let mut left_node = left_root.node_as_mut();
- let mut right_node = right_root.node_as_mut();
+ let mut left_node = left_root.borrow_mut();
+ let mut right_node = right_root.borrow_mut();
loop {
let mut split_edge = match search_node(left_node, key) {
/// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty.
fn fix_top(&mut self) {
- while self.height() > 0 && self.node_as_ref().len() == 0 {
+ while self.height() > 0 && self.len() == 0 {
self.pop_internal_level();
}
}
self.fix_top();
{
- let mut cur_node = self.node_as_mut();
+ let mut cur_node = self.borrow_mut();
while let Internal(node) = cur_node.force() {
let mut last_kv = node.last_kv().consider_for_balancing();
self.fix_top();
{
- let mut cur_node = self.node_as_mut();
+ let mut cur_node = self.borrow_mut();
while let Internal(node) = cur_node.force() {
let mut first_kv = node.first_kv().consider_for_balancing();
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect();
+ /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
/// let buf2 = buf.split_off(1);
/// assert_eq!(buf, [1]);
/// assert_eq!(buf2, [2, 3]);
/// (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
/// (1, 21), (2, 34), (4, 55)].into();
///
- /// assert_eq!(deque.binary_search_by_key(&13, |&(a,b)| b), Ok(9));
- /// assert_eq!(deque.binary_search_by_key(&4, |&(a,b)| b), Err(7));
- /// assert_eq!(deque.binary_search_by_key(&100, |&(a,b)| b), Err(13));
- /// let r = deque.binary_search_by_key(&1, |&(a,b)| b);
+ /// assert_eq!(deque.binary_search_by_key(&13, |&(a, b)| b), Ok(9));
+ /// assert_eq!(deque.binary_search_by_key(&4, |&(a, b)| b), Err(7));
+ /// assert_eq!(deque.binary_search_by_key(&100, |&(a, b)| b), Err(13));
+ /// let r = deque.binary_search_by_key(&1, |&(a, b)| b);
/// assert!(matches!(r, Ok(1..=4)));
/// ```
#[unstable(feature = "vecdeque_binary_search", issue = "78021")]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![deny(unsafe_op_in_unsafe_fn)]
-#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))]
+#![feature(rustc_allow_const_fn_unstable)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![cfg_attr(test, feature(new_uninit))]
#![feature(never_type)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
-#![feature(optin_builtin_traits)]
+#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
+#![cfg_attr(not(bootstrap), feature(auto_traits))]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
-#![cfg_attr(not(bootstrap), feature(unsized_fn_params))]
-#![cfg_attr(bootstrap, feature(unsized_locals))]
+#![feature(unsized_fn_params)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
impl<T, A: AllocRef> RawVec<T, A> {
/// Like `new`, but parameterized over the choice of allocator for
/// the returned `RawVec`.
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))]
+ #[rustc_allow_const_fn_unstable(const_fn)]
pub const fn new_in(alloc: A) -> Self {
// `cap: 0` means "unallocated". zero-sized types are ignored.
Self { ptr: Unique::dangling(), cap: 0, alloc }
}
/// Returns a shared reference to the allocator backing this `RawVec`.
- pub fn alloc(&self) -> &A {
+ pub fn alloc_ref(&self) -> &A {
&self.alloc
}
- /// Returns a mutable reference to the allocator backing this `RawVec`.
- pub fn alloc_mut(&mut self) -> &mut A {
- &mut self.alloc
- }
-
fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
if mem::size_of::<T>() == 0 || self.cap == 0 {
None
use core::mem::{self, size_of};
use core::ptr;
+use crate::alloc::{AllocRef, Global};
use crate::borrow::ToOwned;
use crate::boxed::Box;
use crate::vec::Vec;
// `core::slice::SliceExt` - we need to supply these functions for the
// `test_permutations` test
mod hack {
+ use core::alloc::AllocRef;
+
use crate::boxed::Box;
use crate::vec::Vec;
// We shouldn't add inline attribute to this since this is used in
// `vec!` macro mostly and causes perf regression. See #71204 for
// discussion and perf results.
- pub fn into_vec<T>(b: Box<[T]>) -> Vec<T> {
+ pub fn into_vec<T, A: AllocRef>(b: Box<[T], A>) -> Vec<T, A> {
unsafe {
let len = b.len();
- let b = Box::into_raw(b);
- Vec::from_raw_parts(b as *mut T, len, len)
+ let (b, alloc) = Box::into_raw_with_alloc(b);
+ Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
}
}
#[inline]
- pub fn to_vec<T>(s: &[T]) -> Vec<T>
- where
- T: Clone,
- {
- let mut vec = Vec::with_capacity(s.len());
- vec.extend_from_slice(s);
- vec
+ pub fn to_vec<T: ConvertVec, A: AllocRef>(s: &[T], alloc: A) -> Vec<T, A> {
+ T::to_vec(s, alloc)
+ }
+
+ pub trait ConvertVec {
+ fn to_vec<A: AllocRef>(s: &[Self], alloc: A) -> Vec<Self, A>
+ where
+ Self: Sized;
+ }
+
+ impl<T: Clone> ConvertVec for T {
+ #[inline]
+ default fn to_vec<A: AllocRef>(s: &[Self], alloc: A) -> Vec<Self, A> {
+ struct DropGuard<'a, T, A: AllocRef> {
+ vec: &'a mut Vec<T, A>,
+ num_init: usize,
+ }
+ impl<'a, T, A: AllocRef> Drop for DropGuard<'a, T, A> {
+ #[inline]
+ fn drop(&mut self) {
+ // SAFETY:
+ // items were marked initialized in the loop below
+ unsafe {
+ self.vec.set_len(self.num_init);
+ }
+ }
+ }
+ let mut vec = Vec::with_capacity_in(s.len(), alloc);
+ let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
+ let slots = guard.vec.spare_capacity_mut();
+ // .take(slots.len()) is necessary for LLVM to remove bounds checks
+ // and has better codegen than zip.
+ for (i, b) in s.iter().enumerate().take(slots.len()) {
+ guard.num_init = i;
+ slots[i].write(b.clone());
+ }
+ core::mem::forget(guard);
+ // SAFETY:
+ // the vec was allocated and initialized above to at least this length.
+ unsafe {
+ vec.set_len(s.len());
+ }
+ vec
+ }
+ }
+
+ impl<T: Copy> ConvertVec for T {
+ #[inline]
+ fn to_vec<A: AllocRef>(s: &[Self], alloc: A) -> Vec<Self, A> {
+ let mut v = Vec::with_capacity_in(s.len(), alloc);
+ // SAFETY:
+ // allocated above with the capacity of `s`, and initialize to `s.len()` in
+ // ptr::copy_to_non_overlapping below.
+ unsafe {
+ s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
+ v.set_len(s.len());
+ }
+ v
+ }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn to_vec(&self) -> Vec<T>
+ where
+ T: Clone,
+ {
+ self.to_vec_in(Global)
+ }
+
+ /// Copies `self` into a new `Vec` with an allocator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(allocator_api)]
+ ///
+ /// use std::alloc::System;
+ ///
+ /// let s = [10, 40, 30];
+ /// let x = s.to_vec_in(System);
+ /// // Here, `s` and `x` can be modified independently.
+ /// ```
+ #[inline]
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ pub fn to_vec_in<A: AllocRef>(&self, alloc: A) -> Vec<T, A>
where
T: Clone,
{
// N.B., see the `hack` module in this file for more details.
- hack::to_vec(self)
+ hack::to_vec(self, alloc)
}
/// Converts `self` into a vector without clones or allocation.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn into_vec(self: Box<Self>) -> Vec<T> {
+ pub fn into_vec<A: AllocRef>(self: Box<Self, A>) -> Vec<T, A> {
// N.B., see the `hack` module in this file for more details.
hack::into_vec(self)
}
#[cfg(test)]
fn to_owned(&self) -> Vec<T> {
- hack::to_vec(self)
+ hack::to_vec(self, Global)
}
fn clone_into(&self, target: &mut Vec<T>) {
use core::ptr::{self, NonNull};
use core::slice::{self, SliceIndex};
+use crate::alloc::{AllocRef, Global};
use crate::borrow::{Cow, ToOwned};
use crate::boxed::Box;
use crate::collections::TryReserveError;
/// [`&`]: ../../std/primitive.reference.html
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
-pub struct Vec<T> {
- buf: RawVec<T>,
+pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> {
+ buf: RawVec<T, A>,
len: usize,
}
#[inline]
#[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub const fn new() -> Vec<T> {
+ pub const fn new() -> Self {
Vec { buf: RawVec::NEW, len: 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn with_capacity(capacity: usize) -> Vec<T> {
- Vec { buf: RawVec::with_capacity(capacity), len: 0 }
+ pub fn with_capacity(capacity: usize) -> Self {
+ Self::with_capacity_in(capacity, Global)
}
- /// Decomposes a `Vec<T>` into its raw components.
+ /// Creates a `Vec<T>` directly from the raw components of another vector.
///
- /// 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`].
+ /// # Safety
///
- /// 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.
+ /// This is highly unsafe, due to the number of invariants that aren't
+ /// checked:
///
- /// [`from_raw_parts`]: Vec::from_raw_parts
+ /// * `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(vec_into_raw_parts)]
- /// let v: Vec<i32> = vec![-1, 0, 1];
+ /// use std::ptr;
+ /// use std::mem;
///
- /// let (ptr, len, cap) = v.into_raw_parts();
+ /// let v = vec![1, 2, 3];
///
- /// 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;
+ // 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);
///
- /// Vec::from_raw_parts(ptr, len, cap)
- /// };
- /// assert_eq!(rebuilt, [4294967295, 0, 1]);
+ /// // 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]);
+ /// }
/// ```
- #[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())
+ #[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) }
}
+}
- /// Creates a `Vec<T>` directly from the raw components of another vector.
+impl<T, A: AllocRef> 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
///
/// # Examples
///
/// ```
+ /// #![feature(allocator_api)]
+ ///
+ /// use std::alloc::System;
+ ///
/// use std::ptr;
/// use std::mem;
///
- /// let v = vec![1, 2, 3];
+ /// 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
/// let p = v.as_mut_ptr();
/// let len = v.len();
/// let cap = v.capacity();
+ /// let alloc = v.alloc_ref();
///
/// unsafe {
/// // Overwrite memory with 4, 5, 6
/// }
///
/// // Put everything back together into a Vec
- /// let rebuilt = Vec::from_raw_parts(p, len, cap);
+ /// let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone());
/// assert_eq!(rebuilt, [4, 5, 6]);
/// }
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec<T> {
- unsafe { Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } }
+ #[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.alloc_ref()) };
+ (ptr, len, capacity, alloc)
}
/// Returns the number of elements the vector can hold without
/// assert_eq!(slice.into_vec().capacity(), 3);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn into_boxed_slice(mut self) -> Box<[T]> {
+ pub fn into_boxed_slice(mut self) -> Box<[T], A> {
unsafe {
self.shrink_to_fit();
let me = ManuallyDrop::new(self);
/// }
/// x.set_len(size);
/// }
- /// assert_eq!(&*x, &[0,1,2,3]);
+ /// assert_eq!(&*x, &[0, 1, 2, 3]);
/// ```
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
#[inline]
ptr
}
+ /// Returns a reference to the underlying allocator.
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ #[inline]
+ pub fn alloc_ref(&self) -> &A {
+ self.buf.alloc_ref()
+ }
+
/// Forces the length of the vector to `new_len`.
///
/// This is a low-level operation that maintains none of the normal
/// assert_eq!(v, &[]);
/// ```
#[stable(feature = "drain", since = "1.6.0")]
- pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
+ pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
where
R: RangeBounds<usize>,
{
/// # Examples
///
/// ```
- /// let mut vec = vec![1,2,3];
+ /// 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 {
+ pub fn split_off(&mut self, at: usize) -> Self
+ where
+ A: Clone,
+ {
#[cold]
#[inline(never)]
fn assert_failed(at: usize, len: usize) -> ! {
if at == 0 {
// the new vector can take over the original buffer and avoid the copy
- return mem::replace(self, Vec::with_capacity(self.capacity()));
+ return mem::replace(
+ self,
+ Vec::with_capacity_in(self.capacity(), self.alloc_ref().clone()),
+ );
}
let other_len = self.len - at;
- let mut other = Vec::with_capacity(other_len);
+ let mut other = Vec::with_capacity_in(other_len, self.alloc_ref().clone());
// Unsafely `set_len` and copy items to `other`.
unsafe {
#[inline]
pub fn leak<'a>(self) -> &'a mut [T]
where
- T: 'a, // Technically not needed, but kept to be explicit.
+ A: 'a,
{
Box::leak(self.into_boxed_slice())
}
}
}
-impl<T: Clone> Vec<T> {
+impl<T: Clone, A: AllocRef> 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
}
}
-impl<T> Vec<T> {
+impl<T, A: AllocRef> 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);
}
}
-impl<T: PartialEq> Vec<T> {
+impl<T: PartialEq, A: AllocRef> Vec<T, A> {
/// Removes consecutive repeated elements in the vector according to the
/// [`PartialEq`] trait implementation.
///
}
}
-impl<T> Vec<T> {
+impl<T, A: AllocRef> Vec<T, A> {
/// Removes the first instance of `item` from the vector if the item exists.
///
/// This method will be removed soon.
#[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)
+ <T as SpecFromElem>::from_elem(elem, n, Global)
+}
+
+#[doc(hidden)]
+#[unstable(feature = "allocator_api", issue = "32838")]
+pub fn from_elem_in<T: Clone, A: AllocRef>(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(elem: Self, n: usize) -> Vec<Self>;
+ fn from_elem<A: AllocRef>(elem: Self, n: usize, alloc: A) -> Vec<Self, A>;
}
impl<T: Clone> SpecFromElem for T {
- default fn from_elem(elem: Self, n: usize) -> Vec<Self> {
- let mut v = Vec::with_capacity(n);
+ default fn from_elem<A: AllocRef>(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(elem: i8, n: usize) -> Vec<i8> {
+ fn from_elem<A: AllocRef>(elem: i8, n: usize, alloc: A) -> Vec<i8, A> {
if elem == 0 {
- return Vec { buf: RawVec::with_capacity_zeroed(n), len: n };
+ return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
}
unsafe {
- let mut v = Vec::with_capacity(n);
+ 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(elem: u8, n: usize) -> Vec<u8> {
+ fn from_elem<A: AllocRef>(elem: u8, n: usize, alloc: A) -> Vec<u8, A> {
if elem == 0 {
- return Vec { buf: RawVec::with_capacity_zeroed(n), len: n };
+ return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
}
unsafe {
- let mut v = Vec::with_capacity(n);
+ 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(elem: T, n: usize) -> Vec<T> {
+ fn from_elem<A: AllocRef>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
if elem.is_zero() {
- return Vec { buf: RawVec::with_capacity_zeroed(n), len: n };
+ return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
}
- let mut v = Vec::with_capacity(n);
+ let mut v = Vec::with_capacity_in(n, alloc);
v.extend_with(n, ExtendElement(elem));
v
}
////////////////////////////////////////////////////////////////////////////////
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ops::Deref for Vec<T> {
+impl<T, A: AllocRef> ops::Deref for Vec<T, A> {
type Target = [T];
fn deref(&self) -> &[T] {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ops::DerefMut for Vec<T> {
+impl<T, A: AllocRef> 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> Clone for Vec<T> {
+impl<T: Clone, A: AllocRef + Clone> Clone for Vec<T, A> {
#[cfg(not(test))]
- fn clone(&self) -> Vec<T> {
- <[T]>::to_vec(&**self)
+ fn clone(&self) -> Self {
+ let alloc = self.alloc_ref().clone();
+ <[T]>::to_vec_in(&**self, alloc)
}
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
// `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) -> Vec<T> {
- crate::slice::to_vec(&**self)
+ fn clone(&self) -> Self {
+ let alloc = self.alloc_ref().clone();
+ crate::slice::to_vec(&**self, alloc)
}
- fn clone_from(&mut self, other: &Vec<T>) {
- other.as_slice().clone_into(self);
+ 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> Hash for Vec<T> {
+impl<T: Hash, A: AllocRef> Hash for Vec<T, A> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&**self, state)
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]>> Index<I> for Vec<T> {
+impl<T, I: SliceIndex<[T]>, A: AllocRef> Index<I> for Vec<T, A> {
type Output = I::Output;
#[inline]
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]>> IndexMut<I> for Vec<T> {
+impl<T, I: SliceIndex<[T]>, A: AllocRef> 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> IntoIterator for Vec<T> {
+impl<T, A: AllocRef> IntoIterator for Vec<T, A> {
type Item = T;
- type IntoIter = IntoIter<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
/// }
/// ```
#[inline]
- fn into_iter(self) -> IntoIter<T> {
+ fn into_iter(self) -> IntoIter<T, A> {
unsafe {
let mut me = ManuallyDrop::new(self);
+ let alloc = ptr::read(me.alloc_ref());
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
buf: NonNull::new_unchecked(begin),
phantom: PhantomData,
cap,
+ alloc,
ptr: begin,
end,
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a Vec<T> {
+impl<'a, T, A: AllocRef> IntoIterator for &'a Vec<T, A> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a mut Vec<T> {
+impl<'a, T, A: AllocRef> IntoIterator for &'a mut Vec<T, A> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Extend<T> for Vec<T> {
+impl<T, A: AllocRef> 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())
}
}
-impl<'a, T: 'a> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T>
-where
- T: Copy,
-{
- // reuses the extend specialization for T: Copy
+// 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 {
- 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
+ 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)
}
}
fn spec_extend(&mut self, iter: I);
}
-impl<T, I> SpecExtend<T, I> for Vec<T>
+impl<T, I, A: AllocRef> SpecExtend<T, I> for Vec<T, A>
where
I: Iterator<Item = T>,
{
}
}
-impl<T, I> SpecExtend<T, I> for Vec<T>
+impl<T, I, A: AllocRef> SpecExtend<T, I> for Vec<T, A>
where
I: TrustedLen<Item = T>,
{
}
}
-impl<T> SpecExtend<T, IntoIter<T>> for Vec<T> {
+impl<T, A: AllocRef> 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 _);
}
}
-impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec<T>
+impl<'a, T: 'a, I, A: AllocRef + 'a> SpecExtend<&'a T, I> for Vec<T, A>
where
I: Iterator<Item = &'a T>,
T: Clone,
}
}
-impl<'a, T: 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T>
+impl<'a, T: 'a, A: AllocRef + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
where
T: Copy,
{
}
}
-impl<T> Vec<T> {
+impl<T, A: AllocRef> 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) {
/// ```
#[inline]
#[stable(feature = "vec_splice", since = "1.21.0")]
- pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter>
+ pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
where
R: RangeBounds<usize>,
I: IntoIterator<Item = T>,
/// 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>
+ pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
///
/// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice
#[stable(feature = "extend_ref", since = "1.2.0")]
-impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<T> {
+impl<'a, T: Copy + 'a, A: AllocRef + '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())
}
macro_rules! __impl_slice_eq1 {
([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => {
#[$stability]
- impl<A, B, $($vars)*> PartialEq<$rhs> for $lhs
+ impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
where
- A: PartialEq<B>,
+ T: PartialEq<U>,
$($ty: $bound)?
{
#[inline]
}
}
-__impl_slice_eq1! { [] Vec<A>, Vec<B>, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Vec<A>, &[B], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Vec<A>, &mut [B], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] &[A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
-__impl_slice_eq1! { [] &mut [A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
-__impl_slice_eq1! { [] Vec<A>, [B], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
-__impl_slice_eq1! { [] [A], Vec<B>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
-__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B> where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Cow<'_, [A]>, &[B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N], #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: AllocRef] Vec<T, A>, Vec<U, A>, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: AllocRef] Vec<T, A>, &[U], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: AllocRef] Vec<T, A>, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: AllocRef] &[T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [A: AllocRef] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [A: AllocRef] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
+__impl_slice_eq1! { [A: AllocRef] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] }
+__impl_slice_eq1! { [A: AllocRef] 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: AllocRef, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [A: AllocRef, 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?
/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison).
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for Vec<T> {
+impl<T: PartialOrd, A: AllocRef> PartialOrd for Vec<T, A> {
#[inline]
- fn partial_cmp(&self, other: &Vec<T>) -> Option<Ordering> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for Vec<T> {}
+impl<T: Eq, A: AllocRef> 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> Ord for Vec<T> {
+impl<T: Ord, A: AllocRef> Ord for Vec<T, A> {
#[inline]
- fn cmp(&self, other: &Vec<T>) -> Ordering {
+ fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&**self, &**other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T> Drop for Vec<T> {
+unsafe impl<#[may_dangle] T, A: AllocRef> Drop for Vec<T, A> {
fn drop(&mut self) {
unsafe {
// use drop for [T]
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for Vec<T> {
+impl<T: fmt::Debug, A: AllocRef> 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> AsRef<Vec<T>> for Vec<T> {
- fn as_ref(&self) -> &Vec<T> {
+impl<T, A: AllocRef> 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> AsMut<Vec<T>> for Vec<T> {
- fn as_mut(&mut self) -> &mut Vec<T> {
+impl<T, A: AllocRef> 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> AsRef<[T]> for Vec<T> {
+impl<T, A: AllocRef> AsRef<[T]> for Vec<T, A> {
fn as_ref(&self) -> &[T] {
self
}
}
#[stable(feature = "vec_as_mut", since = "1.5.0")]
-impl<T> AsMut<[T]> for Vec<T> {
+impl<T, A: AllocRef> AsMut<[T]> for Vec<T, A> {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
#[cfg(test)]
fn from(s: &[T]) -> Vec<T> {
- crate::slice::to_vec(s)
+ crate::slice::to_vec(s, Global)
}
}
}
#[cfg(test)]
fn from(s: &mut [T]) -> Vec<T> {
- crate::slice::to_vec(s)
+ crate::slice::to_vec(s, Global)
}
}
// note: test pulls in libstd, which causes errors here
#[cfg(not(test))]
#[stable(feature = "vec_from_box", since = "1.18.0")]
-impl<T> From<Box<[T]>> for Vec<T> {
- fn from(s: Box<[T]>) -> Vec<T> {
- s.into_vec()
+impl<T, A: AllocRef> 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> From<Vec<T>> for Box<[T]> {
- fn from(v: Vec<T>) -> Box<[T]> {
+impl<T, A: AllocRef> From<Vec<T, A>> for Box<[T], A> {
+ fn from(v: Vec<T, A>) -> Self {
v.into_boxed_slice()
}
}
}
#[stable(feature = "array_try_from_vec", since = "1.48.0")]
-impl<T, const N: usize> TryFrom<Vec<T>> for [T; N] {
- type Error = Vec<T>;
+impl<T, A: AllocRef, 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.
/// assert_eq!(a, b' ');
/// assert_eq!(b, b'd');
/// ```
- fn try_from(mut vec: Vec<T>) -> Result<[T; N], Vec<T>> {
+ fn try_from(mut vec: Vec<T, A>) -> Result<[T; N], Vec<T, A>> {
if vec.len() != N {
return Err(vec);
}
/// let iter: std::vec::IntoIter<_> = v.into_iter();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IntoIter<T> {
+pub struct IntoIter<T, #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = 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> fmt::Debug for IntoIter<T> {
+impl<T: fmt::Debug, A: AllocRef> 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> IntoIter<T> {
+impl<T, A: AllocRef> IntoIter<T, A> {
/// Returns the remaining items of this iterator as a slice.
///
/// # Examples
unsafe { &mut *self.as_raw_mut_slice() }
}
+ /// Returns a reference to the underlying allocator.
+ #[unstable(feature = "allocator_api", issue = "32838")]
+ #[inline]
+ pub fn alloc_ref(&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())
}
}
#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
-impl<T> AsRef<[T]> for IntoIter<T> {
+impl<T, A: AllocRef> 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> Send for IntoIter<T> {}
+unsafe impl<T: Send, A: AllocRef + Send> Send for IntoIter<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Sync for IntoIter<T> {}
+unsafe impl<T: Sync, A: AllocRef> Sync for IntoIter<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Iterator for IntoIter<T> {
+impl<T, A: AllocRef> Iterator for IntoIter<T, A> {
type Item = T;
#[inline]
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> DoubleEndedIterator for IntoIter<T> {
+impl<T, A: AllocRef> DoubleEndedIterator for IntoIter<T, A> {
#[inline]
fn next_back(&mut self) -> Option<T> {
if self.end == self.ptr {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for IntoIter<T> {
+impl<T, A: AllocRef> ExactSizeIterator for IntoIter<T, A> {
fn is_empty(&self) -> bool {
self.ptr == self.end
}
}
#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for IntoIter<T> {}
+impl<T, A: AllocRef> FusedIterator for IntoIter<T, A> {}
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for IntoIter<T> {}
+unsafe impl<T, A: AllocRef> 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> TrustedRandomAccess for IntoIter<T>
+unsafe impl<T, A: AllocRef> TrustedRandomAccess for IntoIter<T, A>
where
T: Copy,
{
}
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
-impl<T: Clone> Clone for IntoIter<T> {
- fn clone(&self) -> IntoIter<T> {
- self.as_slice().to_owned().into_iter()
+impl<T: Clone, A: AllocRef + 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> Drop for IntoIter<T> {
+unsafe impl<#[may_dangle] T, A: AllocRef> Drop for IntoIter<T, A> {
fn drop(&mut self) {
- struct DropGuard<'a, T>(&'a mut IntoIter<T>);
+ struct DropGuard<'a, T, A: AllocRef>(&'a mut IntoIter<T, A>);
- impl<T> Drop for DropGuard<'_, T> {
+ impl<T, A: AllocRef> Drop for DropGuard<'_, T, A> {
fn drop(&mut self) {
- // RawVec handles deallocation
- let _ = unsafe { RawVec::from_raw_parts(self.0.buf.as_ptr(), self.0.cap) };
+ 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);
+ }
}
}
}
#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<T> InPlaceIterable for IntoIter<T> {}
+unsafe impl<T, A: AllocRef> InPlaceIterable for IntoIter<T, A> {}
#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<T> SourceIter for IntoIter<T> {
- type Source = IntoIter<T>;
+unsafe impl<T, A: AllocRef> SourceIter for IntoIter<T, A> {
+ type Source = Self;
#[inline]
unsafe fn as_inner(&mut self) -> &mut Self::Source {
/// let iter: std::vec::Drain<_> = v.drain(..);
/// ```
#[stable(feature = "drain", since = "1.6.0")]
-pub struct Drain<'a, T: 'a> {
+pub struct Drain<
+ 'a,
+ T: 'a,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef + '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>>,
+ vec: NonNull<Vec<T, A>>,
}
#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
+impl<T: fmt::Debug, A: AllocRef> 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> Drain<'a, T> {
+impl<'a, T, A: AllocRef> Drain<'a, T, A> {
/// Returns the remaining items of this iterator as a slice.
///
/// # Examples
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 alloc_ref(&self) -> &A {
+ unsafe { self.vec.as_ref().alloc_ref() }
+ }
}
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
-impl<'a, T> AsRef<[T]> for Drain<'a, T> {
+impl<'a, T, A: AllocRef> 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> Sync for Drain<'_, T> {}
+unsafe impl<T: Sync, A: Sync + AllocRef> Sync for Drain<'_, T, A> {}
#[stable(feature = "drain", since = "1.6.0")]
-unsafe impl<T: Send> Send for Drain<'_, T> {}
+unsafe impl<T: Send, A: Send + AllocRef> Send for Drain<'_, T, A> {}
#[stable(feature = "drain", since = "1.6.0")]
-impl<T> Iterator for Drain<'_, T> {
+impl<T, A: AllocRef> Iterator for Drain<'_, T, A> {
type Item = T;
#[inline]
}
#[stable(feature = "drain", since = "1.6.0")]
-impl<T> DoubleEndedIterator for Drain<'_, T> {
+impl<T, A: AllocRef> 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> Drop for Drain<'_, T> {
+impl<T, A: AllocRef> 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>(&'r mut Drain<'a, T>);
+ struct DropGuard<'r, 'a, T, A: AllocRef>(&'r mut Drain<'a, T, A>);
- impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> {
+ impl<'r, 'a, T, A: AllocRef> 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.
}
#[stable(feature = "drain", since = "1.6.0")]
-impl<T> ExactSizeIterator for Drain<'_, T> {
+impl<T, A: AllocRef> ExactSizeIterator for Drain<'_, T, A> {
fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for Drain<'_, T> {}
+unsafe impl<T, A: AllocRef> TrustedLen for Drain<'_, T, A> {}
#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Drain<'_, T> {}
+impl<T, A: AllocRef> FusedIterator for Drain<'_, T, A> {}
/// A splicing iterator for `Vec`.
///
/// ```
#[derive(Debug)]
#[stable(feature = "vec_splice", since = "1.21.0")]
-pub struct Splice<'a, I: Iterator + 'a> {
- drain: Drain<'a, I::Item>,
+pub struct Splice<
+ 'a,
+ I: Iterator + 'a,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef + 'a = Global,
+> {
+ drain: Drain<'a, I::Item, A>,
replace_with: I,
}
#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator> Iterator for Splice<'_, I> {
+impl<I: Iterator, A: AllocRef> Iterator for Splice<'_, I, A> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
}
#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator> DoubleEndedIterator for Splice<'_, I> {
+impl<I: Iterator, A: AllocRef> 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> ExactSizeIterator for Splice<'_, I> {}
+impl<I: Iterator, A: AllocRef> ExactSizeIterator for Splice<'_, I, A> {}
#[stable(feature = "vec_splice", since = "1.21.0")]
-impl<I: Iterator> Drop for Splice<'_, I> {
+impl<I: Iterator, A: AllocRef> Drop for Splice<'_, I, A> {
fn drop(&mut self) {
self.drain.by_ref().for_each(drop);
}
/// Private helper methods for `Splice::drop`
-impl<T> Drain<'_, T> {
+impl<T, A: AllocRef> 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.
/// ```
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
#[derive(Debug)]
-pub struct DrainFilter<'a, T, F>
-where
+pub struct DrainFilter<
+ 'a,
+ T,
+ F,
+ #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global,
+> where
F: FnMut(&mut T) -> bool,
{
- vec: &'a mut Vec<T>,
+ 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.
panic_flag: bool,
}
+impl<T, F, A: AllocRef> 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 alloc_ref(&self) -> &A {
+ self.vec.alloc_ref()
+ }
+}
+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F> Iterator for DrainFilter<'_, T, F>
+impl<T, F, A: AllocRef> Iterator for DrainFilter<'_, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
}
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F> Drop for DrainFilter<'_, T, F>
+impl<T, F, A: AllocRef> Drop for DrainFilter<'_, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
fn drop(&mut self) {
- struct BackshiftOnDrop<'a, 'b, T, F>
+ struct BackshiftOnDrop<'a, 'b, T, F, A: AllocRef>
where
F: FnMut(&mut T) -> bool,
{
- drain: &'b mut DrainFilter<'a, T, F>,
+ drain: &'b mut DrainFilter<'a, T, F, A>,
}
- impl<'a, 'b, T, F> Drop for BackshiftOnDrop<'a, 'b, T, F>
+ impl<'a, 'b, T, F, A: AllocRef> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
#[test]
fn test_from_iter_specialization_with_iterator_adapters() {
- fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {};
+ fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {}
let src: Vec<usize> = vec![0usize; 256];
let srcptr = src.as_ptr();
let iter = src
struct Check {
index: usize,
drop_counts: Rc<Mutex<Vec<usize>>>,
- };
+ }
impl Drop for Check {
fn drop(&mut self) {
struct Check {
index: usize,
drop_counts: Rc<Mutex<Vec<usize>>>,
- };
+ }
impl Drop for Check {
fn drop(&mut self) {
-Subproject commit 8b8ea53b56f519dd7780defdd4254daaec892584
+Subproject commit af078ecc0b069ec594982f92d4c6c58af99efbb5
/// must not overflow (i.e., the rounded value must be less than
/// or equal to `usize::MAX`).
#[stable(feature = "alloc_layout", since = "1.28.0")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
+ #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
#[inline]
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
if !align.is_power_of_two() {
/// The minimum size in bytes for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
+ #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
#[inline]
pub const fn size(&self) -> usize {
self.size_
/// The minimum byte alignment for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
+ #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
#[inline]
pub const fn align(&self) -> usize {
self.align_.get()
/// Returns an immutable slice of all elements that have not been yielded
/// yet.
- fn as_slice(&self) -> &[T] {
+ #[unstable(feature = "array_value_iter_slice", issue = "65798")]
+ pub fn as_slice(&self) -> &[T] {
// SAFETY: We know that all elements within `alive` are properly initialized.
unsafe {
let slice = self.data.get_unchecked(self.alive.clone());
}
/// Returns a mutable slice of all elements that have not been yielded yet.
- fn as_mut_slice(&mut self) -> &mut [T] {
+ #[unstable(feature = "array_value_iter_slice", issue = "65798")]
+ pub fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: We know that all elements within `alive` are properly initialized.
unsafe {
let slice = self.data.get_unchecked_mut(self.alive.clone());
/// # Examples
///
/// ```
- /// #![feature(bool_to_option)]
- ///
/// assert_eq!(false.then(|| 0), None);
/// assert_eq!(true.then(|| 0), Some(0));
/// ```
- #[unstable(feature = "bool_to_option", issue = "64260")]
+ #[stable(feature = "lazy_bool_to_option", since = "1.50.0")]
#[inline]
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
if self { Some(f()) } else { None }
/// # Examples
///
/// ```
- /// #![feature(refcell_take)]
/// use std::cell::RefCell;
///
/// let c = RefCell::new(5);
/// assert_eq!(five, 5);
/// assert_eq!(c.into_inner(), 0);
/// ```
- #[unstable(feature = "refcell_take", issue = "71395")]
+ #[stable(feature = "refcell_take", since = "1.50.0")]
pub fn take(&self) -> T {
self.replace(Default::default())
}
/// # Examples
///
/// ```
- /// #![feature(clamp)]
- ///
/// assert!((-3).clamp(-2, 1) == -2);
/// assert!(0.clamp(-2, 1) == 0);
/// assert!(2.clamp(-2, 1) == 1);
/// ```
#[must_use]
- #[unstable(feature = "clamp", issue = "44095")]
+ #[stable(feature = "clamp", since = "1.50.0")]
fn clamp(self, min: Self, max: Self) -> Self
where
Self: Sized,
/// ```
/// use std::fmt;
///
- /// struct Foo { nb: i32 };
+ /// struct Foo { nb: i32 }
///
/// impl Foo {
/// fn new(nb: i32) -> Foo {
///
/// let read_future = poll_fn(read_line);
/// assert_eq!(read_future.await, "Hello, World!".to_owned());
-/// # };
+/// # }
/// ```
#[unstable(feature = "future_poll_fn", issue = "72302")]
pub fn poll_fn<T, F>(f: F) -> PollFn<F>
/// let num_leading = unsafe { ctlz_nonzero(x) };
/// assert_eq!(num_leading, 3);
/// ```
- #[rustc_const_unstable(feature = "constctlz", issue = "none")]
+ #[rustc_const_stable(feature = "constctlz", since = "1.50.0")]
pub fn ctlz_nonzero<T: Copy>(x: T) -> T;
/// Returns the number of trailing unset bits (zeroes) in an integer type `T`.
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
-use crate::ops::Try;
-use crate::usize;
+use crate::{ops::Try, usize};
/// An iterator that links two iterators together, in a chain.
///
--- /dev/null
+use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess};
+use crate::iter::{FusedIterator, TrustedLen};
+use crate::ops::Try;
+
+/// An iterator that clones the elements of an underlying iterator.
+///
+/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`cloned`]: Iterator::cloned
+/// [`Iterator`]: trait.Iterator.html
+#[stable(feature = "iter_cloned", since = "1.1.0")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[derive(Clone, Debug)]
+pub struct Cloned<I> {
+ it: I,
+}
+
+impl<I> Cloned<I> {
+ pub(in crate::iter) fn new(it: I) -> Cloned<I> {
+ Cloned { it }
+ }
+}
+
+fn clone_try_fold<T: Clone, Acc, R>(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R {
+ move |acc, elt| f(acc, elt.clone())
+}
+
+#[stable(feature = "iter_cloned", since = "1.1.0")]
+impl<'a, I, T: 'a> Iterator for Cloned<I>
+where
+ I: Iterator<Item = &'a T>,
+ T: Clone,
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ self.it.next().cloned()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.it.size_hint()
+ }
+
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ self.it.try_fold(init, clone_try_fold(f))
+ }
+
+ fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
+ where
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.it.map(T::clone).fold(init, f)
+ }
+
+ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
+ where
+ Self: TrustedRandomAccess,
+ {
+ // SAFETY: the caller must uphold the contract for
+ // `Iterator::__iterator_get_unchecked`.
+ unsafe { try_get_unchecked(&mut self.it, idx).clone() }
+ }
+}
+
+#[stable(feature = "iter_cloned", since = "1.1.0")]
+impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
+where
+ I: DoubleEndedIterator<Item = &'a T>,
+ T: Clone,
+{
+ fn next_back(&mut self) -> Option<T> {
+ self.it.next_back().cloned()
+ }
+
+ fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ self.it.try_rfold(init, clone_try_fold(f))
+ }
+
+ fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
+ where
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.it.map(T::clone).rfold(init, f)
+ }
+}
+
+#[stable(feature = "iter_cloned", since = "1.1.0")]
+impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
+where
+ I: ExactSizeIterator<Item = &'a T>,
+ T: Clone,
+{
+ fn len(&self) -> usize {
+ self.it.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.it.is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<'a, I, T: 'a> FusedIterator for Cloned<I>
+where
+ I: FusedIterator<Item = &'a T>,
+ T: Clone,
+{
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<I> TrustedRandomAccess for Cloned<I>
+where
+ I: TrustedRandomAccess,
+{
+ #[inline]
+ fn may_have_side_effect() -> bool {
+ true
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<'a, I, T: 'a> TrustedLen for Cloned<I>
+where
+ I: TrustedLen<Item = &'a T>,
+ T: Clone,
+{
+}
--- /dev/null
+use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess};
+use crate::iter::{FusedIterator, TrustedLen};
+use crate::ops::Try;
+
+/// An iterator that copies the elements of an underlying iterator.
+///
+/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`copied`]: Iterator::copied
+/// [`Iterator`]: trait.Iterator.html
+#[stable(feature = "iter_copied", since = "1.36.0")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[derive(Clone, Debug)]
+pub struct Copied<I> {
+ it: I,
+}
+
+impl<I> Copied<I> {
+ pub(in crate::iter) fn new(it: I) -> Copied<I> {
+ Copied { it }
+ }
+}
+
+fn copy_fold<T: Copy, Acc>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc {
+ move |acc, &elt| f(acc, elt)
+}
+
+fn copy_try_fold<T: Copy, Acc, R>(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R {
+ move |acc, &elt| f(acc, elt)
+}
+
+#[stable(feature = "iter_copied", since = "1.36.0")]
+impl<'a, I, T: 'a> Iterator for Copied<I>
+where
+ I: Iterator<Item = &'a T>,
+ T: Copy,
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ self.it.next().copied()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.it.size_hint()
+ }
+
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ self.it.try_fold(init, copy_try_fold(f))
+ }
+
+ fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
+ where
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.it.fold(init, copy_fold(f))
+ }
+
+ fn nth(&mut self, n: usize) -> Option<T> {
+ self.it.nth(n).copied()
+ }
+
+ fn last(self) -> Option<T> {
+ self.it.last().copied()
+ }
+
+ fn count(self) -> usize {
+ self.it.count()
+ }
+
+ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
+ where
+ Self: TrustedRandomAccess,
+ {
+ // SAFETY: the caller must uphold the contract for
+ // `Iterator::__iterator_get_unchecked`.
+ *unsafe { try_get_unchecked(&mut self.it, idx) }
+ }
+}
+
+#[stable(feature = "iter_copied", since = "1.36.0")]
+impl<'a, I, T: 'a> DoubleEndedIterator for Copied<I>
+where
+ I: DoubleEndedIterator<Item = &'a T>,
+ T: Copy,
+{
+ fn next_back(&mut self) -> Option<T> {
+ self.it.next_back().copied()
+ }
+
+ fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ self.it.try_rfold(init, copy_try_fold(f))
+ }
+
+ fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
+ where
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.it.rfold(init, copy_fold(f))
+ }
+}
+
+#[stable(feature = "iter_copied", since = "1.36.0")]
+impl<'a, I, T: 'a> ExactSizeIterator for Copied<I>
+where
+ I: ExactSizeIterator<Item = &'a T>,
+ T: Copy,
+{
+ fn len(&self) -> usize {
+ self.it.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.it.is_empty()
+ }
+}
+
+#[stable(feature = "iter_copied", since = "1.36.0")]
+impl<'a, I, T: 'a> FusedIterator for Copied<I>
+where
+ I: FusedIterator<Item = &'a T>,
+ T: Copy,
+{
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<I> TrustedRandomAccess for Copied<I>
+where
+ I: TrustedRandomAccess,
+{
+ #[inline]
+ fn may_have_side_effect() -> bool {
+ I::may_have_side_effect()
+ }
+}
+
+#[stable(feature = "iter_copied", since = "1.36.0")]
+unsafe impl<'a, I, T: 'a> TrustedLen for Copied<I>
+where
+ I: TrustedLen<Item = &'a T>,
+ T: Copy,
+{
+}
--- /dev/null
+use crate::{iter::FusedIterator, ops::Try};
+
+/// An iterator that repeats endlessly.
+///
+/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`cycle`]: Iterator::cycle
+/// [`Iterator`]: trait.Iterator.html
+#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Cycle<I> {
+ orig: I,
+ iter: I,
+}
+
+impl<I: Clone> Cycle<I> {
+ pub(in crate::iter) fn new(iter: I) -> Cycle<I> {
+ Cycle { orig: iter.clone(), iter }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> Iterator for Cycle<I>
+where
+ I: Clone + Iterator,
+{
+ type Item = <I as Iterator>::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<<I as Iterator>::Item> {
+ match self.iter.next() {
+ None => {
+ self.iter = self.orig.clone();
+ self.iter.next()
+ }
+ y => y,
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ // the cycle iterator is either empty or infinite
+ match self.orig.size_hint() {
+ sz @ (0, Some(0)) => sz,
+ (0, _) => (0, None),
+ _ => (usize::MAX, None),
+ }
+ }
+
+ #[inline]
+ fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
+ where
+ F: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ // fully iterate the current iterator. this is necessary because
+ // `self.iter` may be empty even when `self.orig` isn't
+ acc = self.iter.try_fold(acc, &mut f)?;
+ self.iter = self.orig.clone();
+
+ // complete a full cycle, keeping track of whether the cycled
+ // iterator is empty or not. we need to return early in case
+ // of an empty iterator to prevent an infinite loop
+ let mut is_empty = true;
+ acc = self.iter.try_fold(acc, |acc, x| {
+ is_empty = false;
+ f(acc, x)
+ })?;
+
+ if is_empty {
+ return try { acc };
+ }
+
+ loop {
+ self.iter = self.orig.clone();
+ acc = self.iter.try_fold(acc, &mut f)?;
+ }
+ }
+
+ // No `fold` override, because `fold` doesn't make much sense for `Cycle`,
+ // and we can't do anything better than the default.
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
--- /dev/null
+use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess};
+use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
+use crate::ops::{Add, AddAssign, Try};
+
+/// An iterator that yields the current count and the element during iteration.
+///
+/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`enumerate`]: Iterator::enumerate
+/// [`Iterator`]: trait.Iterator.html
+#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Enumerate<I> {
+ iter: I,
+ count: usize,
+}
+impl<I> Enumerate<I> {
+ pub(in crate::iter) fn new(iter: I) -> Enumerate<I> {
+ Enumerate { iter, count: 0 }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> Iterator for Enumerate<I>
+where
+ I: Iterator,
+{
+ type Item = (usize, <I as Iterator>::Item);
+
+ /// # Overflow Behavior
+ ///
+ /// The method does no guarding against overflows, so enumerating more than
+ /// `usize::MAX` elements either produces the wrong result or panics. If
+ /// debug assertions are enabled, a panic is guaranteed.
+ ///
+ /// # Panics
+ ///
+ /// Might panic if the index of the element overflows a `usize`.
+ #[inline]
+ fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
+ let a = self.iter.next()?;
+ let i = self.count;
+ // Possible undefined overflow.
+ AddAssign::add_assign(&mut self.count, 1);
+ Some((i, a))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> {
+ let a = self.iter.nth(n)?;
+ // Possible undefined overflow.
+ let i = Add::add(self.count, n);
+ self.count = Add::add(i, 1);
+ Some((i, a))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.iter.count()
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ #[inline]
+ fn enumerate<'a, T, Acc, R>(
+ count: &'a mut usize,
+ mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a,
+ ) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, item| {
+ let acc = fold(acc, (*count, item));
+ // Possible undefined overflow.
+ AddAssign::add_assign(count, 1);
+ acc
+ }
+ }
+
+ self.iter.try_fold(init, enumerate(&mut self.count, fold))
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn enumerate<T, Acc>(
+ mut count: usize,
+ mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
+ ) -> impl FnMut(Acc, T) -> Acc {
+ move |acc, item| {
+ let acc = fold(acc, (count, item));
+ // Possible undefined overflow.
+ AddAssign::add_assign(&mut count, 1);
+ acc
+ }
+ }
+
+ self.iter.fold(init, enumerate(self.count, fold))
+ }
+
+ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
+ where
+ Self: TrustedRandomAccess,
+ {
+ // SAFETY: the caller must uphold the contract for
+ // `Iterator::__iterator_get_unchecked`.
+ let value = unsafe { try_get_unchecked(&mut self.iter, idx) };
+ (Add::add(self.count, idx), value)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> DoubleEndedIterator for Enumerate<I>
+where
+ I: ExactSizeIterator + DoubleEndedIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
+ let a = self.iter.next_back()?;
+ let len = self.iter.len();
+ // Can safely add, `ExactSizeIterator` promises that the number of
+ // elements fits into a `usize`.
+ Some((self.count + len, a))
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<(usize, <I as Iterator>::Item)> {
+ let a = self.iter.nth_back(n)?;
+ let len = self.iter.len();
+ // Can safely add, `ExactSizeIterator` promises that the number of
+ // elements fits into a `usize`.
+ Some((self.count + len, a))
+ }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ // Can safely add and subtract the count, as `ExactSizeIterator` promises
+ // that the number of elements fits into a `usize`.
+ fn enumerate<T, Acc, R>(
+ mut count: usize,
+ mut fold: impl FnMut(Acc, (usize, T)) -> R,
+ ) -> impl FnMut(Acc, T) -> R {
+ move |acc, item| {
+ count -= 1;
+ fold(acc, (count, item))
+ }
+ }
+
+ let count = self.count + self.iter.len();
+ self.iter.try_rfold(init, enumerate(count, fold))
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ // Can safely add and subtract the count, as `ExactSizeIterator` promises
+ // that the number of elements fits into a `usize`.
+ fn enumerate<T, Acc>(
+ mut count: usize,
+ mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
+ ) -> impl FnMut(Acc, T) -> Acc {
+ move |acc, item| {
+ count -= 1;
+ fold(acc, (count, item))
+ }
+ }
+
+ let count = self.count + self.iter.len();
+ self.iter.rfold(init, enumerate(count, fold))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> ExactSizeIterator for Enumerate<I>
+where
+ I: ExactSizeIterator,
+{
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<I> TrustedRandomAccess for Enumerate<I>
+where
+ I: TrustedRandomAccess,
+{
+ fn may_have_side_effect() -> bool {
+ I::may_have_side_effect()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, I: Iterator> SourceIter for Enumerate<I>
+where
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {}
--- /dev/null
+use crate::fmt;
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::ops::Try;
+
+/// An iterator that filters the elements of `iter` with `predicate`.
+///
+/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`filter`]: Iterator::filter
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct Filter<I, P> {
+ iter: I,
+ predicate: P,
+}
+impl<I, P> Filter<I, P> {
+ pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter<I, P> {
+ Filter { iter, predicate }
+ }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, P> fmt::Debug for Filter<I, P> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Filter").field("iter", &self.iter).finish()
+ }
+}
+
+fn filter_fold<T, Acc>(
+ mut predicate: impl FnMut(&T) -> bool,
+ mut fold: impl FnMut(Acc, T) -> Acc,
+) -> impl FnMut(Acc, T) -> Acc {
+ move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
+}
+
+fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>(
+ predicate: &'a mut impl FnMut(&T) -> bool,
+ mut fold: impl FnMut(Acc, T) -> R + 'a,
+) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator, P> Iterator for Filter<I, P>
+where
+ P: FnMut(&I::Item) -> bool,
+{
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<I::Item> {
+ self.iter.find(&mut self.predicate)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper) // can't know a lower bound, due to the predicate
+ }
+
+ // this special case allows the compiler to make `.filter(_).count()`
+ // branchless. Barring perfect branch prediction (which is unattainable in
+ // the general case), this will be much faster in >90% of cases (containing
+ // virtually all real workloads) and only a tiny bit slower in the rest.
+ //
+ // Having this specialization thus allows us to write `.filter(p).count()`
+ // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is
+ // less readable and also less backwards-compatible to Rust before 1.10.
+ //
+ // Using the branchless version will also simplify the LLVM byte code, thus
+ // leaving more budget for LLVM optimizations.
+ #[inline]
+ fn count(self) -> usize {
+ #[inline]
+ fn to_usize<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize {
+ move |x| predicate(&x) as usize
+ }
+
+ self.iter.map(to_usize(self.predicate)).sum()
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold))
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.fold(init, filter_fold(self.predicate, fold))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
+where
+ P: FnMut(&I::Item) -> bool,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<I::Item> {
+ self.iter.rfind(&mut self.predicate)
+ }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold))
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.rfold(init, filter_fold(self.predicate, fold))
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, P, I: Iterator> SourceIter for Filter<I, P>
+where
+ P: FnMut(&I::Item) -> bool,
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
--- /dev/null
+use crate::fmt;
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator that uses `f` to both filter and map elements from `iter`.
+///
+/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`filter_map`]: Iterator::filter_map
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct FilterMap<I, F> {
+ iter: I,
+ f: F,
+}
+impl<I, F> FilterMap<I, F> {
+ pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap<I, F> {
+ FilterMap { iter, f }
+ }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, F> fmt::Debug for FilterMap<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FilterMap").field("iter", &self.iter).finish()
+ }
+}
+
+fn filter_map_fold<T, B, Acc>(
+ mut f: impl FnMut(T) -> Option<B>,
+ mut fold: impl FnMut(Acc, B) -> Acc,
+) -> impl FnMut(Acc, T) -> Acc {
+ move |acc, item| match f(item) {
+ Some(x) => fold(acc, x),
+ None => acc,
+ }
+}
+
+fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>(
+ f: &'a mut impl FnMut(T) -> Option<B>,
+ mut fold: impl FnMut(Acc, B) -> R + 'a,
+) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, item| match f(item) {
+ Some(x) => fold(acc, x),
+ None => try { acc },
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
+where
+ F: FnMut(I::Item) -> Option<B>,
+{
+ type Item = B;
+
+ #[inline]
+ fn next(&mut self) -> Option<B> {
+ self.iter.find_map(&mut self.f)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper) // can't know a lower bound, due to the predicate
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold))
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.fold(init, filter_map_fold(self.f, fold))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
+where
+ F: FnMut(I::Item) -> Option<B>,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<B> {
+ #[inline]
+ fn find<T, B>(
+ f: &mut impl FnMut(T) -> Option<B>,
+ ) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
+ move |(), x| match f(x) {
+ Some(x) => ControlFlow::Break(x),
+ None => ControlFlow::CONTINUE,
+ }
+ }
+
+ self.iter.try_rfold((), find(&mut self.f)).break_value()
+ }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold))
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.rfold(init, filter_map_fold(self.f, fold))
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for FilterMap<I, F>
+where
+ F: FnMut(I::Item) -> Option<B>,
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> where
+ F: FnMut(I::Item) -> Option<B>
+{
+}
use crate::fmt;
+use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map};
use crate::ops::Try;
-use super::super::{DoubleEndedIterator, Fuse, FusedIterator, Iterator};
-use super::Map;
-
/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
pub struct FlatMap<I, U: IntoIterator, F> {
inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>,
}
+
impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
- pub(in super::super) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
+ pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
FlatMap { inner: FlattenCompat::new(iter.map(f)) }
}
}
-use super::InPlaceIterable;
use crate::intrinsics;
-use crate::iter::adapters::zip::try_get_unchecked;
-use crate::iter::adapters::SourceIter;
-use crate::iter::TrustedRandomAccess;
-use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
+use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter};
+use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedRandomAccess};
use crate::ops::Try;
/// An iterator that yields `None` forever after the underlying iterator
--- /dev/null
+use crate::fmt;
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::ops::Try;
+
+/// An iterator that calls a function with a reference to each element before
+/// yielding it.
+///
+/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`inspect`]: Iterator::inspect
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct Inspect<I, F> {
+ iter: I,
+ f: F,
+}
+impl<I, F> Inspect<I, F> {
+ pub(in crate::iter) fn new(iter: I, f: F) -> Inspect<I, F> {
+ Inspect { iter, f }
+ }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, F> fmt::Debug for Inspect<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Inspect").field("iter", &self.iter).finish()
+ }
+}
+
+impl<I: Iterator, F> Inspect<I, F>
+where
+ F: FnMut(&I::Item),
+{
+ #[inline]
+ fn do_inspect(&mut self, elt: Option<I::Item>) -> Option<I::Item> {
+ if let Some(ref a) = elt {
+ (self.f)(a);
+ }
+
+ elt
+ }
+}
+
+fn inspect_fold<T, Acc>(
+ mut f: impl FnMut(&T),
+ mut fold: impl FnMut(Acc, T) -> Acc,
+) -> impl FnMut(Acc, T) -> Acc {
+ move |acc, item| {
+ f(&item);
+ fold(acc, item)
+ }
+}
+
+fn inspect_try_fold<'a, T, Acc, R>(
+ f: &'a mut impl FnMut(&T),
+ mut fold: impl FnMut(Acc, T) -> R + 'a,
+) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, item| {
+ f(&item);
+ fold(acc, item)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator, F> Iterator for Inspect<I, F>
+where
+ F: FnMut(&I::Item),
+{
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<I::Item> {
+ let next = self.iter.next();
+ self.do_inspect(next)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.fold(init, inspect_fold(self.f, fold))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
+where
+ F: FnMut(&I::Item),
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<I::Item> {
+ let next = self.iter.next_back();
+ self.do_inspect(next)
+ }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.rfold(init, inspect_fold(self.f, fold))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
+where
+ F: FnMut(&I::Item),
+{
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, I: Iterator, F> SourceIter for Inspect<I, F>
+where
+ F: FnMut(&I::Item),
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> where F: FnMut(&I::Item) {}
--- /dev/null
+use crate::fmt;
+use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess};
+use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
+use crate::ops::Try;
+
+/// An iterator that maps the values of `iter` with `f`.
+///
+/// This `struct` is created by the [`map`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`map`]: Iterator::map
+/// [`Iterator`]: trait.Iterator.html
+///
+/// # Notes about side effects
+///
+/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that
+/// you can also [`map`] backwards:
+///
+/// ```rust
+/// let v: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
+///
+/// assert_eq!(v, [4, 3, 2]);
+/// ```
+///
+/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html
+///
+/// But if your closure has state, iterating backwards may act in a way you do
+/// not expect. Let's go through an example. First, in the forward direction:
+///
+/// ```rust
+/// let mut c = 0;
+///
+/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// .map(|letter| { c += 1; (letter, c) }) {
+/// println!("{:?}", pair);
+/// }
+/// ```
+///
+/// This will print "('a', 1), ('b', 2), ('c', 3)".
+///
+/// Now consider this twist where we add a call to `rev`. This version will
+/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed,
+/// but the values of the counter still go in order. This is because `map()` is
+/// still being called lazily on each item, but we are popping items off the
+/// back of the vector now, instead of shifting them from the front.
+///
+/// ```rust
+/// let mut c = 0;
+///
+/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// .map(|letter| { c += 1; (letter, c) })
+/// .rev() {
+/// println!("{:?}", pair);
+/// }
+/// ```
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct Map<I, F> {
+ iter: I,
+ f: F,
+}
+impl<I, F> Map<I, F> {
+ pub(in crate::iter) fn new(iter: I, f: F) -> Map<I, F> {
+ Map { iter, f }
+ }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, F> fmt::Debug for Map<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Map").field("iter", &self.iter).finish()
+ }
+}
+
+fn map_fold<T, B, Acc>(
+ mut f: impl FnMut(T) -> B,
+ mut g: impl FnMut(Acc, B) -> Acc,
+) -> impl FnMut(Acc, T) -> Acc {
+ move |acc, elt| g(acc, f(elt))
+}
+
+fn map_try_fold<'a, T, B, Acc, R>(
+ f: &'a mut impl FnMut(T) -> B,
+ mut g: impl FnMut(Acc, B) -> R + 'a,
+) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, elt| g(acc, f(elt))
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B, I: Iterator, F> Iterator for Map<I, F>
+where
+ F: FnMut(I::Item) -> B,
+{
+ type Item = B;
+
+ #[inline]
+ fn next(&mut self) -> Option<B> {
+ self.iter.next().map(&mut self.f)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+
+ fn try_fold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
+ where
+ Self: Sized,
+ G: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_fold(init, map_try_fold(&mut self.f, g))
+ }
+
+ fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
+ where
+ G: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.fold(init, map_fold(self.f, g))
+ }
+
+ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
+ where
+ Self: TrustedRandomAccess,
+ {
+ // SAFETY: the caller must uphold the contract for
+ // `Iterator::__iterator_get_unchecked`.
+ unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F>
+where
+ F: FnMut(I::Item) -> B,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<B> {
+ self.iter.next_back().map(&mut self.f)
+ }
+
+ fn try_rfold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
+ where
+ Self: Sized,
+ G: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
+ }
+
+ fn rfold<Acc, G>(self, init: Acc, g: G) -> Acc
+ where
+ G: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.rfold(init, map_fold(self.f, g))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
+where
+ F: FnMut(I::Item) -> B,
+{
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<B, I: FusedIterator, F> FusedIterator for Map<I, F> where F: FnMut(I::Item) -> B {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<B, I, F> TrustedLen for Map<I, F>
+where
+ I: TrustedLen,
+ F: FnMut(I::Item) -> B,
+{
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<I, F> TrustedRandomAccess for Map<I, F>
+where
+ I: TrustedRandomAccess,
+{
+ #[inline]
+ fn may_have_side_effect() -> bool {
+ true
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for Map<I, F>
+where
+ F: FnMut(I::Item) -> B,
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for Map<I, F> where F: FnMut(I::Item) -> B {}
--- /dev/null
+use crate::fmt;
+use crate::iter::{adapters::SourceIter, InPlaceIterable};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator that only accepts elements while `predicate` returns `Some(_)`.
+///
+/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`map_while`]: Iterator::map_while
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
+#[derive(Clone)]
+pub struct MapWhile<I, P> {
+ iter: I,
+ predicate: P,
+}
+
+impl<I, P> MapWhile<I, P> {
+ pub(in crate::iter) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
+ MapWhile { iter, predicate }
+ }
+}
+
+#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
+impl<I: fmt::Debug, P> fmt::Debug for MapWhile<I, P> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MapWhile").field("iter", &self.iter).finish()
+ }
+}
+
+#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
+impl<B, I: Iterator, P> Iterator for MapWhile<I, P>
+where
+ P: FnMut(I::Item) -> Option<B>,
+{
+ type Item = B;
+
+ #[inline]
+ fn next(&mut self) -> Option<B> {
+ let x = self.iter.next()?;
+ (self.predicate)(x)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper) // can't know a lower bound, due to the predicate
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ let Self { iter, predicate } = self;
+ iter.try_fold(init, |acc, x| match predicate(x) {
+ Some(item) => ControlFlow::from_try(fold(acc, item)),
+ None => ControlFlow::Break(try { acc }),
+ })
+ .into_try()
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
+ move |acc, x| Ok(f(acc, x))
+ }
+
+ self.try_fold(init, ok(fold)).unwrap()
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, B, I: Iterator, P> SourceIter for MapWhile<I, P>
+where
+ P: FnMut(I::Item) -> Option<B>,
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<B, I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> where
+ P: FnMut(I::Item) -> Option<B>
+{
+}
-use crate::cmp;
-use crate::fmt;
-use crate::intrinsics;
-use crate::ops::{Add, AddAssign, ControlFlow, Try};
-
-use super::from_fn;
-use super::{
- DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, TrustedLen,
-};
+use crate::iter::{InPlaceIterable, Iterator};
+use crate::ops::{ControlFlow, Try};
mod chain;
+mod cloned;
+mod copied;
+mod cycle;
+mod enumerate;
+mod filter;
+mod filter_map;
mod flatten;
mod fuse;
+mod inspect;
+mod map;
+mod map_while;
+mod peekable;
+mod rev;
+mod scan;
+mod skip;
+mod skip_while;
+mod step_by;
+mod take;
+mod take_while;
mod zip;
-pub use self::chain::Chain;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::flatten::{FlatMap, Flatten};
-pub use self::fuse::Fuse;
-use self::zip::try_get_unchecked;
+pub use self::{
+ chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap,
+ flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev,
+ scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip,
+};
+
+#[stable(feature = "iter_cloned", since = "1.1.0")]
+pub use self::cloned::Cloned;
+
+#[stable(feature = "iterator_step_by", since = "1.28.0")]
+pub use self::step_by::StepBy;
+
+#[stable(feature = "iterator_flatten", since = "1.29.0")]
+pub use self::flatten::Flatten;
+
+#[stable(feature = "iter_copied", since = "1.36.0")]
+pub use self::copied::Copied;
+
+#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
+pub use self::map_while::MapWhile;
+
#[unstable(feature = "trusted_random_access", issue = "none")]
pub use self::zip::TrustedRandomAccess;
-pub use self::zip::Zip;
/// This trait provides transitive access to source-stage in an interator-adapter pipeline
/// under the conditions that
unsafe fn as_inner(&mut self) -> &mut Self::Source;
}
-/// A double-ended iterator with the direction inverted.
-///
-/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`rev`]: Iterator::rev
-/// [`Iterator`]: trait.Iterator.html
-#[derive(Clone, Debug)]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Rev<T> {
- iter: T,
-}
-impl<T> Rev<T> {
- pub(super) fn new(iter: T) -> Rev<T> {
- Rev { iter }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> Iterator for Rev<I>
-where
- I: DoubleEndedIterator,
-{
- type Item = <I as Iterator>::Item;
-
- #[inline]
- fn next(&mut self) -> Option<<I as Iterator>::Item> {
- self.iter.next_back()
- }
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn advance_by(&mut self, n: usize) -> Result<(), usize> {
- self.iter.advance_back_by(n)
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
- self.iter.nth_back(n)
- }
-
- fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- self.iter.try_rfold(init, f)
- }
-
- fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
- where
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.rfold(init, f)
- }
-
- #[inline]
- fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
- where
- P: FnMut(&Self::Item) -> bool,
- {
- self.iter.rfind(predicate)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> DoubleEndedIterator for Rev<I>
-where
- I: DoubleEndedIterator,
-{
- #[inline]
- fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
- self.iter.next()
- }
-
- #[inline]
- fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- self.iter.advance_by(n)
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
- self.iter.nth(n)
- }
-
- fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- self.iter.try_fold(init, f)
- }
-
- fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
- where
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.fold(init, f)
- }
-
- fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
- where
- P: FnMut(&Self::Item) -> bool,
- {
- self.iter.find(predicate)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Rev<I>
-where
- I: ExactSizeIterator + DoubleEndedIterator,
-{
- fn len(&self) -> usize {
- self.iter.len()
- }
-
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I> FusedIterator for Rev<I> where I: FusedIterator + DoubleEndedIterator {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<I> TrustedLen for Rev<I> where I: TrustedLen + DoubleEndedIterator {}
-
-/// An iterator that copies the elements of an underlying iterator.
-///
-/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`copied`]: Iterator::copied
-/// [`Iterator`]: trait.Iterator.html
-#[stable(feature = "iter_copied", since = "1.36.0")]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[derive(Clone, Debug)]
-pub struct Copied<I> {
- it: I,
-}
-
-impl<I> Copied<I> {
- pub(super) fn new(it: I) -> Copied<I> {
- Copied { it }
- }
-}
-
-fn copy_fold<T: Copy, Acc>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc {
- move |acc, &elt| f(acc, elt)
-}
-
-fn copy_try_fold<T: Copy, Acc, R>(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R {
- move |acc, &elt| f(acc, elt)
-}
-
-#[stable(feature = "iter_copied", since = "1.36.0")]
-impl<'a, I, T: 'a> Iterator for Copied<I>
-where
- I: Iterator<Item = &'a T>,
- T: Copy,
-{
- type Item = T;
-
- fn next(&mut self) -> Option<T> {
- self.it.next().copied()
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.it.size_hint()
- }
-
- fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- self.it.try_fold(init, copy_try_fold(f))
- }
-
- fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
- where
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- self.it.fold(init, copy_fold(f))
- }
-
- fn nth(&mut self, n: usize) -> Option<T> {
- self.it.nth(n).copied()
- }
-
- fn last(self) -> Option<T> {
- self.it.last().copied()
- }
-
- fn count(self) -> usize {
- self.it.count()
- }
-
- unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
- where
- Self: TrustedRandomAccess,
- {
- // SAFETY: the caller must uphold the contract for
- // `Iterator::__iterator_get_unchecked`.
- *unsafe { try_get_unchecked(&mut self.it, idx) }
- }
-}
-
-#[stable(feature = "iter_copied", since = "1.36.0")]
-impl<'a, I, T: 'a> DoubleEndedIterator for Copied<I>
-where
- I: DoubleEndedIterator<Item = &'a T>,
- T: Copy,
-{
- fn next_back(&mut self) -> Option<T> {
- self.it.next_back().copied()
- }
-
- fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- self.it.try_rfold(init, copy_try_fold(f))
- }
-
- fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
- where
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- self.it.rfold(init, copy_fold(f))
- }
-}
-
-#[stable(feature = "iter_copied", since = "1.36.0")]
-impl<'a, I, T: 'a> ExactSizeIterator for Copied<I>
-where
- I: ExactSizeIterator<Item = &'a T>,
- T: Copy,
-{
- fn len(&self) -> usize {
- self.it.len()
- }
-
- fn is_empty(&self) -> bool {
- self.it.is_empty()
- }
-}
-
-#[stable(feature = "iter_copied", since = "1.36.0")]
-impl<'a, I, T: 'a> FusedIterator for Copied<I>
-where
- I: FusedIterator<Item = &'a T>,
- T: Copy,
-{
-}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<I> TrustedRandomAccess for Copied<I>
-where
- I: TrustedRandomAccess,
-{
- #[inline]
- fn may_have_side_effect() -> bool {
- I::may_have_side_effect()
- }
-}
-
-#[stable(feature = "iter_copied", since = "1.36.0")]
-unsafe impl<'a, I, T: 'a> TrustedLen for Copied<I>
-where
- I: TrustedLen<Item = &'a T>,
- T: Copy,
-{
-}
-
-/// An iterator that clones the elements of an underlying iterator.
-///
-/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`cloned`]: Iterator::cloned
-/// [`Iterator`]: trait.Iterator.html
-#[stable(feature = "iter_cloned", since = "1.1.0")]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[derive(Clone, Debug)]
-pub struct Cloned<I> {
- it: I,
-}
-impl<I> Cloned<I> {
- pub(super) fn new(it: I) -> Cloned<I> {
- Cloned { it }
- }
-}
-
-fn clone_try_fold<T: Clone, Acc, R>(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R {
- move |acc, elt| f(acc, elt.clone())
-}
-
-#[stable(feature = "iter_cloned", since = "1.1.0")]
-impl<'a, I, T: 'a> Iterator for Cloned<I>
-where
- I: Iterator<Item = &'a T>,
- T: Clone,
-{
- type Item = T;
-
- fn next(&mut self) -> Option<T> {
- self.it.next().cloned()
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.it.size_hint()
- }
-
- fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- self.it.try_fold(init, clone_try_fold(f))
- }
-
- fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
- where
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- self.it.map(T::clone).fold(init, f)
- }
-
- unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
- where
- Self: TrustedRandomAccess,
- {
- // SAFETY: the caller must uphold the contract for
- // `Iterator::__iterator_get_unchecked`.
- unsafe { try_get_unchecked(&mut self.it, idx).clone() }
- }
-}
-
-#[stable(feature = "iter_cloned", since = "1.1.0")]
-impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
-where
- I: DoubleEndedIterator<Item = &'a T>,
- T: Clone,
-{
- fn next_back(&mut self) -> Option<T> {
- self.it.next_back().cloned()
- }
-
- fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- self.it.try_rfold(init, clone_try_fold(f))
- }
-
- fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
- where
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- self.it.map(T::clone).rfold(init, f)
- }
-}
-
-#[stable(feature = "iter_cloned", since = "1.1.0")]
-impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
-where
- I: ExactSizeIterator<Item = &'a T>,
- T: Clone,
-{
- fn len(&self) -> usize {
- self.it.len()
- }
-
- fn is_empty(&self) -> bool {
- self.it.is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<'a, I, T: 'a> FusedIterator for Cloned<I>
-where
- I: FusedIterator<Item = &'a T>,
- T: Clone,
-{
-}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<I> TrustedRandomAccess for Cloned<I>
-where
- I: TrustedRandomAccess,
-{
- #[inline]
- fn may_have_side_effect() -> bool {
- true
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<'a, I, T: 'a> TrustedLen for Cloned<I>
-where
- I: TrustedLen<Item = &'a T>,
- T: Clone,
-{
-}
-
-/// An iterator that repeats endlessly.
-///
-/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`cycle`]: Iterator::cycle
-/// [`Iterator`]: trait.Iterator.html
-#[derive(Clone, Debug)]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Cycle<I> {
- orig: I,
- iter: I,
-}
-impl<I: Clone> Cycle<I> {
- pub(super) fn new(iter: I) -> Cycle<I> {
- Cycle { orig: iter.clone(), iter }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> Iterator for Cycle<I>
-where
- I: Clone + Iterator,
-{
- type Item = <I as Iterator>::Item;
-
- #[inline]
- fn next(&mut self) -> Option<<I as Iterator>::Item> {
- match self.iter.next() {
- None => {
- self.iter = self.orig.clone();
- self.iter.next()
- }
- y => y,
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- // the cycle iterator is either empty or infinite
- match self.orig.size_hint() {
- sz @ (0, Some(0)) => sz,
- (0, _) => (0, None),
- _ => (usize::MAX, None),
- }
- }
-
- #[inline]
- fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
- where
- F: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- // fully iterate the current iterator. this is necessary because
- // `self.iter` may be empty even when `self.orig` isn't
- acc = self.iter.try_fold(acc, &mut f)?;
- self.iter = self.orig.clone();
-
- // complete a full cycle, keeping track of whether the cycled
- // iterator is empty or not. we need to return early in case
- // of an empty iterator to prevent an infinite loop
- let mut is_empty = true;
- acc = self.iter.try_fold(acc, |acc, x| {
- is_empty = false;
- f(acc, x)
- })?;
-
- if is_empty {
- return try { acc };
- }
-
- loop {
- self.iter = self.orig.clone();
- acc = self.iter.try_fold(acc, &mut f)?;
- }
- }
-
- // No `fold` override, because `fold` doesn't make much sense for `Cycle`,
- // and we can't do anything better than the default.
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
-
-/// An iterator for stepping iterators by a custom amount.
-///
-/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
-/// its documentation for more.
-///
-/// [`step_by`]: Iterator::step_by
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "iterator_step_by", since = "1.28.0")]
-#[derive(Clone, Debug)]
-pub struct StepBy<I> {
- iter: I,
- step: usize,
- first_take: bool,
-}
-impl<I> StepBy<I> {
- pub(super) fn new(iter: I, step: usize) -> StepBy<I> {
- assert!(step != 0);
- StepBy { iter, step: step - 1, first_take: true }
- }
-}
-
-#[stable(feature = "iterator_step_by", since = "1.28.0")]
-impl<I> Iterator for StepBy<I>
-where
- I: Iterator,
-{
- type Item = I::Item;
-
- #[inline]
- fn next(&mut self) -> Option<Self::Item> {
- if self.first_take {
- self.first_take = false;
- self.iter.next()
- } else {
- self.iter.nth(self.step)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- #[inline]
- fn first_size(step: usize) -> impl Fn(usize) -> usize {
- move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) }
- }
-
- #[inline]
- fn other_size(step: usize) -> impl Fn(usize) -> usize {
- move |n| n / (step + 1)
- }
-
- let (low, high) = self.iter.size_hint();
-
- if self.first_take {
- let f = first_size(self.step);
- (f(low), high.map(f))
- } else {
- let f = other_size(self.step);
- (f(low), high.map(f))
- }
- }
-
- #[inline]
- fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
- if self.first_take {
- self.first_take = false;
- let first = self.iter.next();
- if n == 0 {
- return first;
- }
- n -= 1;
- }
- // n and self.step are indices, we need to add 1 to get the amount of elements
- // When calling `.nth`, we need to subtract 1 again to convert back to an index
- // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1`
- let mut step = self.step + 1;
- // n + 1 could overflow
- // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
- if n == usize::MAX {
- self.iter.nth(step - 1);
- } else {
- n += 1;
- }
-
- // overflow handling
- loop {
- let mul = n.checked_mul(step);
- {
- if intrinsics::likely(mul.is_some()) {
- return self.iter.nth(mul.unwrap() - 1);
- }
- }
- let div_n = usize::MAX / n;
- let div_step = usize::MAX / step;
- let nth_n = div_n * n;
- let nth_step = div_step * step;
- let nth = if nth_n > nth_step {
- step -= div_n;
- nth_n
- } else {
- n -= div_step;
- nth_step
- };
- self.iter.nth(nth - 1);
- }
- }
-
- fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
- where
- F: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- #[inline]
- fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
- move || iter.nth(step)
- }
-
- if self.first_take {
- self.first_take = false;
- match self.iter.next() {
- None => return try { acc },
- Some(x) => acc = f(acc, x)?,
- }
- }
- from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f)
- }
-
- fn fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
- where
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
- move || iter.nth(step)
- }
-
- if self.first_take {
- self.first_take = false;
- match self.iter.next() {
- None => return acc,
- Some(x) => acc = f(acc, x),
- }
- }
- from_fn(nth(&mut self.iter, self.step)).fold(acc, f)
- }
-}
-
-impl<I> StepBy<I>
-where
- I: ExactSizeIterator,
-{
- // The zero-based index starting from the end of the iterator of the
- // last element. Used in the `DoubleEndedIterator` implementation.
- fn next_back_index(&self) -> usize {
- let rem = self.iter.len() % (self.step + 1);
- if self.first_take {
- if rem == 0 { self.step } else { rem - 1 }
- } else {
- rem
- }
- }
-}
-
-#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
-impl<I> DoubleEndedIterator for StepBy<I>
-where
- I: DoubleEndedIterator + ExactSizeIterator,
-{
- #[inline]
- fn next_back(&mut self) -> Option<Self::Item> {
- self.iter.nth_back(self.next_back_index())
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- // `self.iter.nth_back(usize::MAX)` does the right thing here when `n`
- // is out of bounds because the length of `self.iter` does not exceed
- // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
- // zero-indexed
- let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index());
- self.iter.nth_back(n)
- }
-
- fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
- where
- F: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- #[inline]
- fn nth_back<I: DoubleEndedIterator>(
- iter: &mut I,
- step: usize,
- ) -> impl FnMut() -> Option<I::Item> + '_ {
- move || iter.nth_back(step)
- }
-
- match self.next_back() {
- None => try { init },
- Some(x) => {
- let acc = f(init, x)?;
- from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f)
- }
- }
- }
-
- #[inline]
- fn rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
- where
- Self: Sized,
- F: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn nth_back<I: DoubleEndedIterator>(
- iter: &mut I,
- step: usize,
- ) -> impl FnMut() -> Option<I::Item> + '_ {
- move || iter.nth_back(step)
- }
-
- match self.next_back() {
- None => init,
- Some(x) => {
- let acc = f(init, x);
- from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f)
- }
- }
- }
-}
-
-// StepBy can only make the iterator shorter, so the len will still fit.
-#[stable(feature = "iterator_step_by", since = "1.28.0")]
-impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
-
-/// An iterator that maps the values of `iter` with `f`.
-///
-/// This `struct` is created by the [`map`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`map`]: Iterator::map
-/// [`Iterator`]: trait.Iterator.html
-///
-/// # Notes about side effects
-///
-/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that
-/// you can also [`map`] backwards:
-///
-/// ```rust
-/// let v: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
-///
-/// assert_eq!(v, [4, 3, 2]);
-/// ```
-///
-/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html
-///
-/// But if your closure has state, iterating backwards may act in a way you do
-/// not expect. Let's go through an example. First, in the forward direction:
-///
-/// ```rust
-/// let mut c = 0;
-///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
-/// .map(|letter| { c += 1; (letter, c) }) {
-/// println!("{:?}", pair);
-/// }
-/// ```
-///
-/// This will print "('a', 1), ('b', 2), ('c', 3)".
-///
-/// Now consider this twist where we add a call to `rev`. This version will
-/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed,
-/// but the values of the counter still go in order. This is because `map()` is
-/// still being called lazily on each item, but we are popping items off the
-/// back of the vector now, instead of shifting them from the front.
-///
-/// ```rust
-/// let mut c = 0;
-///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
-/// .map(|letter| { c += 1; (letter, c) })
-/// .rev() {
-/// println!("{:?}", pair);
-/// }
-/// ```
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct Map<I, F> {
- iter: I,
- f: F,
-}
-impl<I, F> Map<I, F> {
- pub(super) fn new(iter: I, f: F) -> Map<I, F> {
- Map { iter, f }
- }
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, F> fmt::Debug for Map<I, F> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Map").field("iter", &self.iter).finish()
- }
-}
-
-fn map_fold<T, B, Acc>(
- mut f: impl FnMut(T) -> B,
- mut g: impl FnMut(Acc, B) -> Acc,
-) -> impl FnMut(Acc, T) -> Acc {
- move |acc, elt| g(acc, f(elt))
-}
-
-fn map_try_fold<'a, T, B, Acc, R>(
- f: &'a mut impl FnMut(T) -> B,
- mut g: impl FnMut(Acc, B) -> R + 'a,
-) -> impl FnMut(Acc, T) -> R + 'a {
- move |acc, elt| g(acc, f(elt))
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<B, I: Iterator, F> Iterator for Map<I, F>
-where
- F: FnMut(I::Item) -> B,
-{
- type Item = B;
-
- #[inline]
- fn next(&mut self) -> Option<B> {
- self.iter.next().map(&mut self.f)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- fn try_fold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
- where
- Self: Sized,
- G: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_fold(init, map_try_fold(&mut self.f, g))
- }
-
- fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
- where
- G: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.fold(init, map_fold(self.f, g))
- }
-
- unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
- where
- Self: TrustedRandomAccess,
- {
- // SAFETY: the caller must uphold the contract for
- // `Iterator::__iterator_get_unchecked`.
- unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F>
-where
- F: FnMut(I::Item) -> B,
-{
- #[inline]
- fn next_back(&mut self) -> Option<B> {
- self.iter.next_back().map(&mut self.f)
- }
-
- fn try_rfold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
- where
- Self: Sized,
- G: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
- }
-
- fn rfold<Acc, G>(self, init: Acc, g: G) -> Acc
- where
- G: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.rfold(init, map_fold(self.f, g))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
-where
- F: FnMut(I::Item) -> B,
-{
- fn len(&self) -> usize {
- self.iter.len()
- }
-
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<B, I: FusedIterator, F> FusedIterator for Map<I, F> where F: FnMut(I::Item) -> B {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<B, I, F> TrustedLen for Map<I, F>
-where
- I: TrustedLen,
- F: FnMut(I::Item) -> B,
-{
-}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<I, F> TrustedRandomAccess for Map<I, F>
-where
- I: TrustedRandomAccess,
-{
- #[inline]
- fn may_have_side_effect() -> bool {
- true
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for Map<I, F>
-where
- F: FnMut(I::Item) -> B,
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for Map<I, F> where F: FnMut(I::Item) -> B {}
-
-/// An iterator that filters the elements of `iter` with `predicate`.
-///
-/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`filter`]: Iterator::filter
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct Filter<I, P> {
- iter: I,
- predicate: P,
-}
-impl<I, P> Filter<I, P> {
- pub(super) fn new(iter: I, predicate: P) -> Filter<I, P> {
- Filter { iter, predicate }
- }
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, P> fmt::Debug for Filter<I, P> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Filter").field("iter", &self.iter).finish()
- }
-}
-
-fn filter_fold<T, Acc>(
- mut predicate: impl FnMut(&T) -> bool,
- mut fold: impl FnMut(Acc, T) -> Acc,
-) -> impl FnMut(Acc, T) -> Acc {
- move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
-}
-
-fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>(
- predicate: &'a mut impl FnMut(&T) -> bool,
- mut fold: impl FnMut(Acc, T) -> R + 'a,
-) -> impl FnMut(Acc, T) -> R + 'a {
- move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, P> Iterator for Filter<I, P>
-where
- P: FnMut(&I::Item) -> bool,
-{
- type Item = I::Item;
-
- #[inline]
- fn next(&mut self) -> Option<I::Item> {
- self.iter.find(&mut self.predicate)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (_, upper) = self.iter.size_hint();
- (0, upper) // can't know a lower bound, due to the predicate
- }
-
- // this special case allows the compiler to make `.filter(_).count()`
- // branchless. Barring perfect branch prediction (which is unattainable in
- // the general case), this will be much faster in >90% of cases (containing
- // virtually all real workloads) and only a tiny bit slower in the rest.
- //
- // Having this specialization thus allows us to write `.filter(p).count()`
- // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is
- // less readable and also less backwards-compatible to Rust before 1.10.
- //
- // Using the branchless version will also simplify the LLVM byte code, thus
- // leaving more budget for LLVM optimizations.
- #[inline]
- fn count(self) -> usize {
- #[inline]
- fn to_usize<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize {
- move |x| predicate(&x) as usize
- }
-
- self.iter.map(to_usize(self.predicate)).sum()
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold))
- }
-
- #[inline]
- fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.fold(init, filter_fold(self.predicate, fold))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
-where
- P: FnMut(&I::Item) -> bool,
-{
- #[inline]
- fn next_back(&mut self) -> Option<I::Item> {
- self.iter.rfind(&mut self.predicate)
- }
-
- #[inline]
- fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold))
- }
-
- #[inline]
- fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.rfold(init, filter_fold(self.predicate, fold))
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, P, I: Iterator> SourceIter for Filter<I, P>
-where
- P: FnMut(&I::Item) -> bool,
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
-
-/// An iterator that uses `f` to both filter and map elements from `iter`.
-///
-/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`filter_map`]: Iterator::filter_map
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct FilterMap<I, F> {
- iter: I,
- f: F,
-}
-impl<I, F> FilterMap<I, F> {
- pub(super) fn new(iter: I, f: F) -> FilterMap<I, F> {
- FilterMap { iter, f }
- }
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, F> fmt::Debug for FilterMap<I, F> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("FilterMap").field("iter", &self.iter).finish()
- }
-}
-
-fn filter_map_fold<T, B, Acc>(
- mut f: impl FnMut(T) -> Option<B>,
- mut fold: impl FnMut(Acc, B) -> Acc,
-) -> impl FnMut(Acc, T) -> Acc {
- move |acc, item| match f(item) {
- Some(x) => fold(acc, x),
- None => acc,
- }
-}
-
-fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>(
- f: &'a mut impl FnMut(T) -> Option<B>,
- mut fold: impl FnMut(Acc, B) -> R + 'a,
-) -> impl FnMut(Acc, T) -> R + 'a {
- move |acc, item| match f(item) {
- Some(x) => fold(acc, x),
- None => try { acc },
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
-where
- F: FnMut(I::Item) -> Option<B>,
-{
- type Item = B;
-
- #[inline]
- fn next(&mut self) -> Option<B> {
- self.iter.find_map(&mut self.f)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (_, upper) = self.iter.size_hint();
- (0, upper) // can't know a lower bound, due to the predicate
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold))
- }
-
- #[inline]
- fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.fold(init, filter_map_fold(self.f, fold))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
-where
- F: FnMut(I::Item) -> Option<B>,
-{
- #[inline]
- fn next_back(&mut self) -> Option<B> {
- #[inline]
- fn find<T, B>(
- f: &mut impl FnMut(T) -> Option<B>,
- ) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
- move |(), x| match f(x) {
- Some(x) => ControlFlow::Break(x),
- None => ControlFlow::CONTINUE,
- }
- }
-
- self.iter.try_rfold((), find(&mut self.f)).break_value()
- }
-
- #[inline]
- fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold))
- }
-
- #[inline]
- fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.rfold(init, filter_map_fold(self.f, fold))
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, B, I: Iterator, F> SourceIter for FilterMap<I, F>
-where
- F: FnMut(I::Item) -> Option<B>,
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> where
- F: FnMut(I::Item) -> Option<B>
-{
-}
-
-/// An iterator that yields the current count and the element during iteration.
-///
-/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`enumerate`]: Iterator::enumerate
-/// [`Iterator`]: trait.Iterator.html
-#[derive(Clone, Debug)]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Enumerate<I> {
- iter: I,
- count: usize,
-}
-impl<I> Enumerate<I> {
- pub(super) fn new(iter: I) -> Enumerate<I> {
- Enumerate { iter, count: 0 }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> Iterator for Enumerate<I>
-where
- I: Iterator,
-{
- type Item = (usize, <I as Iterator>::Item);
-
- /// # Overflow Behavior
- ///
- /// The method does no guarding against overflows, so enumerating more than
- /// `usize::MAX` elements either produces the wrong result or panics. If
- /// debug assertions are enabled, a panic is guaranteed.
- ///
- /// # Panics
- ///
- /// Might panic if the index of the element overflows a `usize`.
- #[inline]
- fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
- let a = self.iter.next()?;
- let i = self.count;
- // Possible undefined overflow.
- AddAssign::add_assign(&mut self.count, 1);
- Some((i, a))
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> {
- let a = self.iter.nth(n)?;
- // Possible undefined overflow.
- let i = Add::add(self.count, n);
- self.count = Add::add(i, 1);
- Some((i, a))
- }
-
- #[inline]
- fn count(self) -> usize {
- self.iter.count()
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- #[inline]
- fn enumerate<'a, T, Acc, R>(
- count: &'a mut usize,
- mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a,
- ) -> impl FnMut(Acc, T) -> R + 'a {
- move |acc, item| {
- let acc = fold(acc, (*count, item));
- // Possible undefined overflow.
- AddAssign::add_assign(count, 1);
- acc
- }
- }
-
- self.iter.try_fold(init, enumerate(&mut self.count, fold))
- }
-
- #[inline]
- fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn enumerate<T, Acc>(
- mut count: usize,
- mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
- ) -> impl FnMut(Acc, T) -> Acc {
- move |acc, item| {
- let acc = fold(acc, (count, item));
- // Possible undefined overflow.
- AddAssign::add_assign(&mut count, 1);
- acc
- }
- }
-
- self.iter.fold(init, enumerate(self.count, fold))
- }
-
- unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
- where
- Self: TrustedRandomAccess,
- {
- // SAFETY: the caller must uphold the contract for
- // `Iterator::__iterator_get_unchecked`.
- let value = unsafe { try_get_unchecked(&mut self.iter, idx) };
- (Add::add(self.count, idx), value)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> DoubleEndedIterator for Enumerate<I>
-where
- I: ExactSizeIterator + DoubleEndedIterator,
-{
- #[inline]
- fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
- let a = self.iter.next_back()?;
- let len = self.iter.len();
- // Can safely add, `ExactSizeIterator` promises that the number of
- // elements fits into a `usize`.
- Some((self.count + len, a))
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<(usize, <I as Iterator>::Item)> {
- let a = self.iter.nth_back(n)?;
- let len = self.iter.len();
- // Can safely add, `ExactSizeIterator` promises that the number of
- // elements fits into a `usize`.
- Some((self.count + len, a))
- }
-
- #[inline]
- fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- // Can safely add and subtract the count, as `ExactSizeIterator` promises
- // that the number of elements fits into a `usize`.
- fn enumerate<T, Acc, R>(
- mut count: usize,
- mut fold: impl FnMut(Acc, (usize, T)) -> R,
- ) -> impl FnMut(Acc, T) -> R {
- move |acc, item| {
- count -= 1;
- fold(acc, (count, item))
- }
- }
-
- let count = self.count + self.iter.len();
- self.iter.try_rfold(init, enumerate(count, fold))
- }
-
- #[inline]
- fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- // Can safely add and subtract the count, as `ExactSizeIterator` promises
- // that the number of elements fits into a `usize`.
- fn enumerate<T, Acc>(
- mut count: usize,
- mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
- ) -> impl FnMut(Acc, T) -> Acc {
- move |acc, item| {
- count -= 1;
- fold(acc, (count, item))
- }
- }
-
- let count = self.count + self.iter.len();
- self.iter.rfold(init, enumerate(count, fold))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Enumerate<I>
-where
- I: ExactSizeIterator,
-{
- fn len(&self) -> usize {
- self.iter.len()
- }
-
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<I> TrustedRandomAccess for Enumerate<I>
-where
- I: TrustedRandomAccess,
-{
- fn may_have_side_effect() -> bool {
- I::may_have_side_effect()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, I: Iterator> SourceIter for Enumerate<I>
-where
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {}
-
-/// An iterator with a `peek()` that returns an optional reference to the next
-/// element.
-///
-/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`peekable`]: Iterator::peekable
-/// [`Iterator`]: trait.Iterator.html
-#[derive(Clone, Debug)]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Peekable<I: Iterator> {
- iter: I,
- /// Remember a peeked value, even if it was None.
- peeked: Option<Option<I::Item>>,
-}
-impl<I: Iterator> Peekable<I> {
- pub(super) fn new(iter: I) -> Peekable<I> {
- Peekable { iter, peeked: None }
- }
-}
-
-// Peekable must remember if a None has been seen in the `.peek()` method.
-// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
-// underlying iterator at most once. This does not by itself make the iterator
-// fused.
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator> Iterator for Peekable<I> {
- type Item = I::Item;
-
- #[inline]
- fn next(&mut self) -> Option<I::Item> {
- match self.peeked.take() {
- Some(v) => v,
- None => self.iter.next(),
- }
- }
-
- #[inline]
- #[rustc_inherit_overflow_checks]
- fn count(mut self) -> usize {
- match self.peeked.take() {
- Some(None) => 0,
- Some(Some(_)) => 1 + self.iter.count(),
- None => self.iter.count(),
- }
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<I::Item> {
- match self.peeked.take() {
- Some(None) => None,
- Some(v @ Some(_)) if n == 0 => v,
- Some(Some(_)) => self.iter.nth(n - 1),
- None => self.iter.nth(n),
- }
- }
-
- #[inline]
- fn last(mut self) -> Option<I::Item> {
- let peek_opt = match self.peeked.take() {
- Some(None) => return None,
- Some(v) => v,
- None => None,
- };
- self.iter.last().or(peek_opt)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let peek_len = match self.peeked {
- Some(None) => return (0, Some(0)),
- Some(Some(_)) => 1,
- None => 0,
- };
- let (lo, hi) = self.iter.size_hint();
- let lo = lo.saturating_add(peek_len);
- let hi = match hi {
- Some(x) => x.checked_add(peek_len),
- None => None,
- };
- (lo, hi)
- }
-
- #[inline]
- fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- let acc = match self.peeked.take() {
- Some(None) => return try { init },
- Some(Some(v)) => f(init, v)?,
- None => init,
- };
- self.iter.try_fold(acc, f)
- }
-
- #[inline]
- fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- let acc = match self.peeked {
- Some(None) => return init,
- Some(Some(v)) => fold(init, v),
- None => init,
- };
- self.iter.fold(acc, fold)
- }
-}
-
-#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
-impl<I> DoubleEndedIterator for Peekable<I>
-where
- I: DoubleEndedIterator,
-{
- #[inline]
- fn next_back(&mut self) -> Option<Self::Item> {
- match self.peeked.as_mut() {
- Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
- Some(None) => None,
- None => self.iter.next_back(),
- }
- }
-
- #[inline]
- fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> R,
- R: Try<Ok = B>,
- {
- match self.peeked.take() {
- Some(None) => try { init },
- Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
- Ok(acc) => f(acc, v),
- Err(e) => {
- self.peeked = Some(Some(v));
- Try::from_error(e)
- }
- },
- None => self.iter.try_rfold(init, f),
- }
- }
-
- #[inline]
- fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- match self.peeked {
- Some(None) => init,
- Some(Some(v)) => {
- let acc = self.iter.rfold(init, &mut fold);
- fold(acc, v)
- }
- None => self.iter.rfold(init, fold),
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I: FusedIterator> FusedIterator for Peekable<I> {}
-
-impl<I: Iterator> Peekable<I> {
- /// Returns a reference to the next() value without advancing the iterator.
- ///
- /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
- /// But if the iteration is over, `None` is returned.
- ///
- /// [`next`]: Iterator::next
- ///
- /// Because `peek()` returns a reference, and many iterators iterate over
- /// references, there can be a possibly confusing situation where the
- /// return value is a double reference. You can see this effect in the
- /// examples below.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let xs = [1, 2, 3];
- ///
- /// let mut iter = xs.iter().peekable();
- ///
- /// // peek() lets us see into the future
- /// assert_eq!(iter.peek(), Some(&&1));
- /// assert_eq!(iter.next(), Some(&1));
- ///
- /// assert_eq!(iter.next(), Some(&2));
- ///
- /// // The iterator does not advance even if we `peek` multiple times
- /// assert_eq!(iter.peek(), Some(&&3));
- /// assert_eq!(iter.peek(), Some(&&3));
- ///
- /// assert_eq!(iter.next(), Some(&3));
- ///
- /// // After the iterator is finished, so is `peek()`
- /// assert_eq!(iter.peek(), None);
- /// assert_eq!(iter.next(), None);
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn peek(&mut self) -> Option<&I::Item> {
- let iter = &mut self.iter;
- self.peeked.get_or_insert_with(|| iter.next()).as_ref()
- }
-
- /// Consume and return the next value of this iterator if a condition is true.
- ///
- /// If `func` returns `true` for the next value of this iterator, consume and return it.
- /// Otherwise, return `None`.
- ///
- /// # Examples
- /// Consume a number if it's equal to 0.
- /// ```
- /// #![feature(peekable_next_if)]
- /// let mut iter = (0..5).peekable();
- /// // The first item of the iterator is 0; consume it.
- /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
- /// // The next item returned is now 1, so `consume` will return `false`.
- /// assert_eq!(iter.next_if(|&x| x == 0), None);
- /// // `next_if` saves the value of the next item if it was not equal to `expected`.
- /// assert_eq!(iter.next(), Some(1));
- /// ```
- ///
- /// Consume any number less than 10.
- /// ```
- /// #![feature(peekable_next_if)]
- /// let mut iter = (1..20).peekable();
- /// // Consume all numbers less than 10
- /// while iter.next_if(|&x| x < 10).is_some() {}
- /// // The next value returned will be 10
- /// assert_eq!(iter.next(), Some(10));
- /// ```
- #[unstable(feature = "peekable_next_if", issue = "72480")]
- pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
- match self.next() {
- Some(matched) if func(&matched) => Some(matched),
- other => {
- // Since we called `self.next()`, we consumed `self.peeked`.
- assert!(self.peeked.is_none());
- self.peeked = Some(other);
- None
- }
- }
- }
-
- /// Consume and return the next item if it is equal to `expected`.
- ///
- /// # Example
- /// Consume a number if it's equal to 0.
- /// ```
- /// #![feature(peekable_next_if)]
- /// let mut iter = (0..5).peekable();
- /// // The first item of the iterator is 0; consume it.
- /// assert_eq!(iter.next_if_eq(&0), Some(0));
- /// // The next item returned is now 1, so `consume` will return `false`.
- /// assert_eq!(iter.next_if_eq(&0), None);
- /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
- /// assert_eq!(iter.next(), Some(1));
- /// ```
- #[unstable(feature = "peekable_next_if", issue = "72480")]
- pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
- where
- T: ?Sized,
- I::Item: PartialEq<T>,
- {
- self.next_if(|next| next == expected)
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
-where
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
-
-/// An iterator that rejects elements while `predicate` returns `true`.
-///
-/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`skip_while`]: Iterator::skip_while
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct SkipWhile<I, P> {
- iter: I,
- flag: bool,
- predicate: P,
-}
-impl<I, P> SkipWhile<I, P> {
- pub(super) fn new(iter: I, predicate: P) -> SkipWhile<I, P> {
- SkipWhile { iter, flag: false, predicate }
- }
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, P> fmt::Debug for SkipWhile<I, P> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SkipWhile").field("iter", &self.iter).field("flag", &self.flag).finish()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, P> Iterator for SkipWhile<I, P>
-where
- P: FnMut(&I::Item) -> bool,
-{
- type Item = I::Item;
-
- #[inline]
- fn next(&mut self) -> Option<I::Item> {
- fn check<'a, T>(
- flag: &'a mut bool,
- pred: &'a mut impl FnMut(&T) -> bool,
- ) -> impl FnMut(&T) -> bool + 'a {
- move |x| {
- if *flag || !pred(x) {
- *flag = true;
- true
- } else {
- false
- }
- }
- }
-
- let flag = &mut self.flag;
- let pred = &mut self.predicate;
- self.iter.find(check(flag, pred))
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (_, upper) = self.iter.size_hint();
- (0, upper) // can't know a lower bound, due to the predicate
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- if !self.flag {
- match self.next() {
- Some(v) => init = fold(init, v)?,
- None => return try { init },
- }
- }
- self.iter.try_fold(init, fold)
- }
-
- #[inline]
- fn fold<Acc, Fold>(mut self, mut init: Acc, mut fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- if !self.flag {
- match self.next() {
- Some(v) => init = fold(init, v),
- None => return init,
- }
- }
- self.iter.fold(init, fold)
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I, P> FusedIterator for SkipWhile<I, P>
-where
- I: FusedIterator,
- P: FnMut(&I::Item) -> bool,
-{
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, P, I: Iterator> SourceIter for SkipWhile<I, P>
-where
- P: FnMut(&I::Item) -> bool,
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> where
- F: FnMut(&I::Item) -> bool
-{
-}
-
-/// An iterator that only accepts elements while `predicate` returns `true`.
-///
-/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`take_while`]: Iterator::take_while
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct TakeWhile<I, P> {
- iter: I,
- flag: bool,
- predicate: P,
-}
-impl<I, P> TakeWhile<I, P> {
- pub(super) fn new(iter: I, predicate: P) -> TakeWhile<I, P> {
- TakeWhile { iter, flag: false, predicate }
- }
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, P> fmt::Debug for TakeWhile<I, P> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("TakeWhile").field("iter", &self.iter).field("flag", &self.flag).finish()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, P> Iterator for TakeWhile<I, P>
-where
- P: FnMut(&I::Item) -> bool,
-{
- type Item = I::Item;
-
- #[inline]
- fn next(&mut self) -> Option<I::Item> {
- if self.flag {
- None
- } else {
- let x = self.iter.next()?;
- if (self.predicate)(&x) {
- Some(x)
- } else {
- self.flag = true;
- None
- }
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.flag {
- (0, Some(0))
- } else {
- let (_, upper) = self.iter.size_hint();
- (0, upper) // can't know a lower bound, due to the predicate
- }
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- fn check<'a, T, Acc, R: Try<Ok = Acc>>(
- flag: &'a mut bool,
- p: &'a mut impl FnMut(&T) -> bool,
- mut fold: impl FnMut(Acc, T) -> R + 'a,
- ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
- move |acc, x| {
- if p(&x) {
- ControlFlow::from_try(fold(acc, x))
- } else {
- *flag = true;
- ControlFlow::Break(try { acc })
- }
- }
- }
-
- if self.flag {
- try { init }
- } else {
- let flag = &mut self.flag;
- let p = &mut self.predicate;
- self.iter.try_fold(init, check(flag, p, fold)).into_try()
- }
- }
-
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I, P> FusedIterator for TakeWhile<I, P>
-where
- I: FusedIterator,
- P: FnMut(&I::Item) -> bool,
-{
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, P, I: Iterator> SourceIter for TakeWhile<I, P>
-where
- P: FnMut(&I::Item) -> bool,
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> where
- F: FnMut(&I::Item) -> bool
-{
-}
-
-/// An iterator that only accepts elements while `predicate` returns `Some(_)`.
-///
-/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`map_while`]: Iterator::map_while
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
-#[derive(Clone)]
-pub struct MapWhile<I, P> {
- iter: I,
- predicate: P,
-}
-
-impl<I, P> MapWhile<I, P> {
- pub(super) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
- MapWhile { iter, predicate }
- }
-}
-
-#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
-impl<I: fmt::Debug, P> fmt::Debug for MapWhile<I, P> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("MapWhile").field("iter", &self.iter).finish()
- }
-}
-
-#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
-impl<B, I: Iterator, P> Iterator for MapWhile<I, P>
-where
- P: FnMut(I::Item) -> Option<B>,
-{
- type Item = B;
-
- #[inline]
- fn next(&mut self) -> Option<B> {
- let x = self.iter.next()?;
- (self.predicate)(x)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (_, upper) = self.iter.size_hint();
- (0, upper) // can't know a lower bound, due to the predicate
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- let Self { iter, predicate } = self;
- iter.try_fold(init, |acc, x| match predicate(x) {
- Some(item) => ControlFlow::from_try(fold(acc, item)),
- None => ControlFlow::Break(try { acc }),
- })
- .into_try()
- }
-
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, B, I: Iterator, P> SourceIter for MapWhile<I, P>
-where
- P: FnMut(I::Item) -> Option<B>,
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<B, I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> where
- P: FnMut(I::Item) -> Option<B>
-{
-}
-
-/// An iterator that skips over `n` elements of `iter`.
-///
-/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`skip`]: Iterator::skip
-/// [`Iterator`]: trait.Iterator.html
-#[derive(Clone, Debug)]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Skip<I> {
- iter: I,
- n: usize,
-}
-impl<I> Skip<I> {
- pub(super) fn new(iter: I, n: usize) -> Skip<I> {
- Skip { iter, n }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> Iterator for Skip<I>
-where
- I: Iterator,
-{
- type Item = <I as Iterator>::Item;
-
- #[inline]
- fn next(&mut self) -> Option<I::Item> {
- if self.n == 0 {
- self.iter.next()
- } else {
- let old_n = self.n;
- self.n = 0;
- self.iter.nth(old_n)
- }
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<I::Item> {
- // Can't just add n + self.n due to overflow.
- if self.n > 0 {
- let to_skip = self.n;
- self.n = 0;
- // nth(n) skips n+1
- self.iter.nth(to_skip - 1)?;
- }
- self.iter.nth(n)
- }
-
- #[inline]
- fn count(mut self) -> usize {
- if self.n > 0 {
- // nth(n) skips n+1
- if self.iter.nth(self.n - 1).is_none() {
- return 0;
- }
- }
- self.iter.count()
- }
-
- #[inline]
- fn last(mut self) -> Option<I::Item> {
- if self.n > 0 {
- // nth(n) skips n+1
- self.iter.nth(self.n - 1)?;
- }
- self.iter.last()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (lower, upper) = self.iter.size_hint();
-
- let lower = lower.saturating_sub(self.n);
- let upper = match upper {
- Some(x) => Some(x.saturating_sub(self.n)),
- None => None,
- };
-
- (lower, upper)
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- let n = self.n;
- self.n = 0;
- if n > 0 {
- // nth(n) skips n+1
- if self.iter.nth(n - 1).is_none() {
- return try { init };
- }
- }
- self.iter.try_fold(init, fold)
- }
-
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- if self.n > 0 {
- // nth(n) skips n+1
- if self.iter.nth(self.n - 1).is_none() {
- return init;
- }
- }
- self.iter.fold(init, fold)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Skip<I> where I: ExactSizeIterator {}
-
-#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")]
-impl<I> DoubleEndedIterator for Skip<I>
-where
- I: DoubleEndedIterator + ExactSizeIterator,
-{
- fn next_back(&mut self) -> Option<Self::Item> {
- if self.len() > 0 { self.iter.next_back() } else { None }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<I::Item> {
- let len = self.len();
- if n < len {
- self.iter.nth_back(n)
- } else {
- if len > 0 {
- // consume the original iterator
- self.iter.nth_back(len - 1);
- }
- None
- }
- }
-
- fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- fn check<T, Acc, R: Try<Ok = Acc>>(
- mut n: usize,
- mut fold: impl FnMut(Acc, T) -> R,
- ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
- move |acc, x| {
- n -= 1;
- let r = fold(acc, x);
- if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
- }
- }
-
- let n = self.len();
- if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
- }
-
- fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_rfold(init, ok(fold)).unwrap()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, I: Iterator> SourceIter for Skip<I>
-where
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {}
-
-/// An iterator that only iterates over the first `n` iterations of `iter`.
-///
-/// This `struct` is created by the [`take`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`take`]: Iterator::take
-/// [`Iterator`]: trait.Iterator.html
-#[derive(Clone, Debug)]
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Take<I> {
- pub(super) iter: I,
- pub(super) n: usize,
-}
-impl<I> Take<I> {
- pub(super) fn new(iter: I, n: usize) -> Take<I> {
- Take { iter, n }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> Iterator for Take<I>
-where
- I: Iterator,
-{
- type Item = <I as Iterator>::Item;
-
- #[inline]
- fn next(&mut self) -> Option<<I as Iterator>::Item> {
- if self.n != 0 {
- self.n -= 1;
- self.iter.next()
- } else {
- None
- }
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<I::Item> {
- if self.n > n {
- self.n -= n + 1;
- self.iter.nth(n)
- } else {
- if self.n > 0 {
- self.iter.nth(self.n - 1);
- self.n = 0;
- }
- None
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.n == 0 {
- return (0, Some(0));
- }
-
- let (lower, upper) = self.iter.size_hint();
-
- let lower = cmp::min(lower, self.n);
-
- let upper = match upper {
- Some(x) if x < self.n => Some(x),
- _ => Some(self.n),
- };
-
- (lower, upper)
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- fn check<'a, T, Acc, R: Try<Ok = Acc>>(
- n: &'a mut usize,
- mut fold: impl FnMut(Acc, T) -> R + 'a,
- ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
- move |acc, x| {
- *n -= 1;
- let r = fold(acc, x);
- if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
- }
- }
-
- if self.n == 0 {
- try { init }
- } else {
- let n = &mut self.n;
- self.iter.try_fold(init, check(n, fold)).into_try()
- }
- }
-
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, I: Iterator> SourceIter for Take<I>
-where
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> {}
-
-#[stable(feature = "double_ended_take_iterator", since = "1.38.0")]
-impl<I> DoubleEndedIterator for Take<I>
-where
- I: DoubleEndedIterator + ExactSizeIterator,
-{
- #[inline]
- fn next_back(&mut self) -> Option<Self::Item> {
- if self.n == 0 {
- None
- } else {
- let n = self.n;
- self.n -= 1;
- self.iter.nth_back(self.iter.len().saturating_sub(n))
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.iter.len();
- if self.n > n {
- let m = len.saturating_sub(self.n) + n;
- self.n -= n + 1;
- self.iter.nth_back(m)
- } else {
- if len > 0 {
- self.iter.nth_back(len - 1);
- }
- None
- }
- }
-
- #[inline]
- fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- if self.n == 0 {
- try { init }
- } else {
- let len = self.iter.len();
- if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
- try { init }
- } else {
- self.iter.try_rfold(init, fold)
- }
- }
- }
-
- #[inline]
- fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- if self.n == 0 {
- init
- } else {
- let len = self.iter.len();
- if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
- init
- } else {
- self.iter.rfold(init, fold)
- }
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I> FusedIterator for Take<I> where I: FusedIterator {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
-
-/// An iterator to maintain state while iterating another iterator.
-///
-/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`scan`]: Iterator::scan
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct Scan<I, St, F> {
- iter: I,
- f: F,
- state: St,
-}
-impl<I, St, F> Scan<I, St, F> {
- pub(super) fn new(iter: I, state: St, f: F) -> Scan<I, St, F> {
- Scan { iter, state, f }
- }
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, St: fmt::Debug, F> fmt::Debug for Scan<I, St, F> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Scan").field("iter", &self.iter).field("state", &self.state).finish()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<B, I, St, F> Iterator for Scan<I, St, F>
-where
- I: Iterator,
- F: FnMut(&mut St, I::Item) -> Option<B>,
-{
- type Item = B;
-
- #[inline]
- fn next(&mut self) -> Option<B> {
- let a = self.iter.next()?;
- (self.f)(&mut self.state, a)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (_, upper) = self.iter.size_hint();
- (0, upper) // can't know a lower bound, due to the scan function
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>(
- state: &'a mut St,
- f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
- mut fold: impl FnMut(Acc, B) -> R + 'a,
- ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
- move |acc, x| match f(state, x) {
- None => ControlFlow::Break(try { acc }),
- Some(x) => ControlFlow::from_try(fold(acc, x)),
- }
- }
-
- let state = &mut self.state;
- let f = &mut self.f;
- self.iter.try_fold(init, scan(state, f, fold)).into_try()
- }
-
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<St, F, B, S: Iterator, I: Iterator> SourceIter for Scan<I, St, F>
-where
- I: SourceIter<Source = S>,
- F: FnMut(&mut St, I::Item) -> Option<B>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<St, F, B, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> where
- F: FnMut(&mut St, I::Item) -> Option<B>
-{
-}
-
-/// An iterator that calls a function with a reference to each element before
-/// yielding it.
-///
-/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`inspect`]: Iterator::inspect
-/// [`Iterator`]: trait.Iterator.html
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct Inspect<I, F> {
- iter: I,
- f: F,
-}
-impl<I, F> Inspect<I, F> {
- pub(super) fn new(iter: I, f: F) -> Inspect<I, F> {
- Inspect { iter, f }
- }
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, F> fmt::Debug for Inspect<I, F> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Inspect").field("iter", &self.iter).finish()
- }
-}
-
-impl<I: Iterator, F> Inspect<I, F>
-where
- F: FnMut(&I::Item),
-{
- #[inline]
- fn do_inspect(&mut self, elt: Option<I::Item>) -> Option<I::Item> {
- if let Some(ref a) = elt {
- (self.f)(a);
- }
-
- elt
- }
-}
-
-fn inspect_fold<T, Acc>(
- mut f: impl FnMut(&T),
- mut fold: impl FnMut(Acc, T) -> Acc,
-) -> impl FnMut(Acc, T) -> Acc {
- move |acc, item| {
- f(&item);
- fold(acc, item)
- }
-}
-
-fn inspect_try_fold<'a, T, Acc, R>(
- f: &'a mut impl FnMut(&T),
- mut fold: impl FnMut(Acc, T) -> R + 'a,
-) -> impl FnMut(Acc, T) -> R + 'a {
- move |acc, item| {
- f(&item);
- fold(acc, item)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, F> Iterator for Inspect<I, F>
-where
- F: FnMut(&I::Item),
-{
- type Item = I::Item;
-
- #[inline]
- fn next(&mut self) -> Option<I::Item> {
- let next = self.iter.next();
- self.do_inspect(next)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
- }
-
- #[inline]
- fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.fold(init, inspect_fold(self.f, fold))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
-where
- F: FnMut(&I::Item),
-{
- #[inline]
- fn next_back(&mut self) -> Option<I::Item> {
- let next = self.iter.next_back();
- self.do_inspect(next)
- }
-
- #[inline]
- fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> R,
- R: Try<Ok = Acc>,
- {
- self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
- }
-
- #[inline]
- fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- self.iter.rfold(init, inspect_fold(self.f, fold))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
-where
- F: FnMut(&I::Item),
-{
- fn len(&self) -> usize {
- self.iter.len()
- }
-
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<S: Iterator, I: Iterator, F> SourceIter for Inspect<I, F>
-where
- F: FnMut(&I::Item),
- I: SourceIter<Source = S>,
-{
- type Source = S;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut S {
- // SAFETY: unsafe function forwarding to unsafe function with the same requirements
- unsafe { SourceIter::as_inner(&mut self.iter) }
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> where F: FnMut(&I::Item) {}
-
/// An iterator adapter that produces output as long as the underlying
/// iterator produces `Result::Ok` values.
///
--- /dev/null
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
+use crate::ops::Try;
+
+/// An iterator with a `peek()` that returns an optional reference to the next
+/// element.
+///
+/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`peekable`]: Iterator::peekable
+/// [`Iterator`]: trait.Iterator.html
+#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Peekable<I: Iterator> {
+ iter: I,
+ /// Remember a peeked value, even if it was None.
+ peeked: Option<Option<I::Item>>,
+}
+
+impl<I: Iterator> Peekable<I> {
+ pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
+ Peekable { iter, peeked: None }
+ }
+}
+
+// Peekable must remember if a None has been seen in the `.peek()` method.
+// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
+// underlying iterator at most once. This does not by itself make the iterator
+// fused.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator> Iterator for Peekable<I> {
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<I::Item> {
+ match self.peeked.take() {
+ Some(v) => v,
+ None => self.iter.next(),
+ }
+ }
+
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn count(mut self) -> usize {
+ match self.peeked.take() {
+ Some(None) => 0,
+ Some(Some(_)) => 1 + self.iter.count(),
+ None => self.iter.count(),
+ }
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<I::Item> {
+ match self.peeked.take() {
+ Some(None) => None,
+ Some(v @ Some(_)) if n == 0 => v,
+ Some(Some(_)) => self.iter.nth(n - 1),
+ None => self.iter.nth(n),
+ }
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<I::Item> {
+ let peek_opt = match self.peeked.take() {
+ Some(None) => return None,
+ Some(v) => v,
+ None => None,
+ };
+ self.iter.last().or(peek_opt)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let peek_len = match self.peeked {
+ Some(None) => return (0, Some(0)),
+ Some(Some(_)) => 1,
+ None => 0,
+ };
+ let (lo, hi) = self.iter.size_hint();
+ let lo = lo.saturating_add(peek_len);
+ let hi = match hi {
+ Some(x) => x.checked_add(peek_len),
+ None => None,
+ };
+ (lo, hi)
+ }
+
+ #[inline]
+ fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ let acc = match self.peeked.take() {
+ Some(None) => return try { init },
+ Some(Some(v)) => f(init, v)?,
+ None => init,
+ };
+ self.iter.try_fold(acc, f)
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ let acc = match self.peeked {
+ Some(None) => return init,
+ Some(Some(v)) => fold(init, v),
+ None => init,
+ };
+ self.iter.fold(acc, fold)
+ }
+}
+
+#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
+impl<I> DoubleEndedIterator for Peekable<I>
+where
+ I: DoubleEndedIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ match self.peeked.as_mut() {
+ Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
+ Some(None) => None,
+ None => self.iter.next_back(),
+ }
+ }
+
+ #[inline]
+ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ match self.peeked.take() {
+ Some(None) => try { init },
+ Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
+ Ok(acc) => f(acc, v),
+ Err(e) => {
+ self.peeked = Some(Some(v));
+ Try::from_error(e)
+ }
+ },
+ None => self.iter.try_rfold(init, f),
+ }
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ match self.peeked {
+ Some(None) => init,
+ Some(Some(v)) => {
+ let acc = self.iter.rfold(init, &mut fold);
+ fold(acc, v)
+ }
+ None => self.iter.rfold(init, fold),
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I: FusedIterator> FusedIterator for Peekable<I> {}
+
+impl<I: Iterator> Peekable<I> {
+ /// Returns a reference to the next() value without advancing the iterator.
+ ///
+ /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
+ /// But if the iteration is over, `None` is returned.
+ ///
+ /// [`next`]: Iterator::next
+ ///
+ /// Because `peek()` returns a reference, and many iterators iterate over
+ /// references, there can be a possibly confusing situation where the
+ /// return value is a double reference. You can see this effect in the
+ /// examples below.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let xs = [1, 2, 3];
+ ///
+ /// let mut iter = xs.iter().peekable();
+ ///
+ /// // peek() lets us see into the future
+ /// assert_eq!(iter.peek(), Some(&&1));
+ /// assert_eq!(iter.next(), Some(&1));
+ ///
+ /// assert_eq!(iter.next(), Some(&2));
+ ///
+ /// // The iterator does not advance even if we `peek` multiple times
+ /// assert_eq!(iter.peek(), Some(&&3));
+ /// assert_eq!(iter.peek(), Some(&&3));
+ ///
+ /// assert_eq!(iter.next(), Some(&3));
+ ///
+ /// // After the iterator is finished, so is `peek()`
+ /// assert_eq!(iter.peek(), None);
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn peek(&mut self) -> Option<&I::Item> {
+ let iter = &mut self.iter;
+ self.peeked.get_or_insert_with(|| iter.next()).as_ref()
+ }
+
+ /// Returns a mutable reference to the next() value without advancing the iterator.
+ ///
+ /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
+ /// But if the iteration is over, `None` is returned.
+ ///
+ /// Because `peek_mut()` returns a reference, and many iterators iterate over
+ /// references, there can be a possibly confusing situation where the
+ /// return value is a double reference. You can see this effect in the examples
+ /// below.
+ ///
+ /// [`next`]: Iterator::next
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(peekable_peek_mut)]
+ /// let mut iter = [1, 2, 3].iter().peekable();
+ ///
+ /// assert_eq!(iter.peek_mut(), Some(&mut &1));
+ /// assert_eq!(iter.next(), Some(&1));
+ ///
+ /// // Peek into the iterator and modify the value which will be returned next
+ /// if let Some(mut p) = iter.peek_mut() {
+ /// if *p == &2 {
+ /// *p = &5;
+ /// }
+ /// }
+ ///
+ /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
+ /// ```
+ #[inline]
+ #[unstable(feature = "peekable_peek_mut", issue = "78302")]
+ pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
+ let iter = &mut self.iter;
+ self.peeked.get_or_insert_with(|| iter.next()).as_mut()
+ }
+
+ /// Consume and return the next value of this iterator if a condition is true.
+ ///
+ /// If `func` returns `true` for the next value of this iterator, consume and return it.
+ /// Otherwise, return `None`.
+ ///
+ /// # Examples
+ /// Consume a number if it's equal to 0.
+ /// ```
+ /// #![feature(peekable_next_if)]
+ /// let mut iter = (0..5).peekable();
+ /// // The first item of the iterator is 0; consume it.
+ /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
+ /// // The next item returned is now 1, so `consume` will return `false`.
+ /// assert_eq!(iter.next_if(|&x| x == 0), None);
+ /// // `next_if` saves the value of the next item if it was not equal to `expected`.
+ /// assert_eq!(iter.next(), Some(1));
+ /// ```
+ ///
+ /// Consume any number less than 10.
+ /// ```
+ /// #![feature(peekable_next_if)]
+ /// let mut iter = (1..20).peekable();
+ /// // Consume all numbers less than 10
+ /// while iter.next_if(|&x| x < 10).is_some() {}
+ /// // The next value returned will be 10
+ /// assert_eq!(iter.next(), Some(10));
+ /// ```
+ #[unstable(feature = "peekable_next_if", issue = "72480")]
+ pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
+ match self.next() {
+ Some(matched) if func(&matched) => Some(matched),
+ other => {
+ // Since we called `self.next()`, we consumed `self.peeked`.
+ assert!(self.peeked.is_none());
+ self.peeked = Some(other);
+ None
+ }
+ }
+ }
+
+ /// Consume and return the next item if it is equal to `expected`.
+ ///
+ /// # Example
+ /// Consume a number if it's equal to 0.
+ /// ```
+ /// #![feature(peekable_next_if)]
+ /// let mut iter = (0..5).peekable();
+ /// // The first item of the iterator is 0; consume it.
+ /// assert_eq!(iter.next_if_eq(&0), Some(0));
+ /// // The next item returned is now 1, so `consume` will return `false`.
+ /// assert_eq!(iter.next_if_eq(&0), None);
+ /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
+ /// assert_eq!(iter.next(), Some(1));
+ /// ```
+ #[unstable(feature = "peekable_next_if", issue = "72480")]
+ pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
+ where
+ T: ?Sized,
+ I::Item: PartialEq<T>,
+ {
+ self.next_if(|next| next == expected)
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
+where
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
--- /dev/null
+use crate::iter::{FusedIterator, TrustedLen};
+use crate::ops::Try;
+
+/// A double-ended iterator with the direction inverted.
+///
+/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`rev`]: Iterator::rev
+/// [`Iterator`]: trait.Iterator.html
+#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Rev<T> {
+ iter: T,
+}
+
+impl<T> Rev<T> {
+ pub(in crate::iter) fn new(iter: T) -> Rev<T> {
+ Rev { iter }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> Iterator for Rev<I>
+where
+ I: DoubleEndedIterator,
+{
+ type Item = <I as Iterator>::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<<I as Iterator>::Item> {
+ self.iter.next_back()
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+ self.iter.advance_back_by(n)
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
+ self.iter.nth_back(n)
+ }
+
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ self.iter.try_rfold(init, f)
+ }
+
+ fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
+ where
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.rfold(init, f)
+ }
+
+ #[inline]
+ fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
+ where
+ P: FnMut(&Self::Item) -> bool,
+ {
+ self.iter.rfind(predicate)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> DoubleEndedIterator for Rev<I>
+where
+ I: DoubleEndedIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
+ self.iter.next()
+ }
+
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+ self.iter.advance_by(n)
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
+ self.iter.nth(n)
+ }
+
+ fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Ok = B>,
+ {
+ self.iter.try_fold(init, f)
+ }
+
+ fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
+ where
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.iter.fold(init, f)
+ }
+
+ fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
+ where
+ P: FnMut(&Self::Item) -> bool,
+ {
+ self.iter.find(predicate)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> ExactSizeIterator for Rev<I>
+where
+ I: ExactSizeIterator + DoubleEndedIterator,
+{
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I> FusedIterator for Rev<I> where I: FusedIterator + DoubleEndedIterator {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<I> TrustedLen for Rev<I> where I: TrustedLen + DoubleEndedIterator {}
--- /dev/null
+use crate::fmt;
+use crate::iter::{adapters::SourceIter, InPlaceIterable};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator to maintain state while iterating another iterator.
+///
+/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`scan`]: Iterator::scan
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct Scan<I, St, F> {
+ iter: I,
+ f: F,
+ state: St,
+}
+
+impl<I, St, F> Scan<I, St, F> {
+ pub(in crate::iter) fn new(iter: I, state: St, f: F) -> Scan<I, St, F> {
+ Scan { iter, state, f }
+ }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, St: fmt::Debug, F> fmt::Debug for Scan<I, St, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Scan").field("iter", &self.iter).field("state", &self.state).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<B, I, St, F> Iterator for Scan<I, St, F>
+where
+ I: Iterator,
+ F: FnMut(&mut St, I::Item) -> Option<B>,
+{
+ type Item = B;
+
+ #[inline]
+ fn next(&mut self) -> Option<B> {
+ let a = self.iter.next()?;
+ (self.f)(&mut self.state, a)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper) // can't know a lower bound, due to the scan function
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>(
+ state: &'a mut St,
+ f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
+ mut fold: impl FnMut(Acc, B) -> R + 'a,
+ ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
+ move |acc, x| match f(state, x) {
+ None => ControlFlow::Break(try { acc }),
+ Some(x) => ControlFlow::from_try(fold(acc, x)),
+ }
+ }
+
+ let state = &mut self.state;
+ let f = &mut self.f;
+ self.iter.try_fold(init, scan(state, f, fold)).into_try()
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
+ move |acc, x| Ok(f(acc, x))
+ }
+
+ self.try_fold(init, ok(fold)).unwrap()
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<St, F, B, S: Iterator, I: Iterator> SourceIter for Scan<I, St, F>
+where
+ I: SourceIter<Source = S>,
+ F: FnMut(&mut St, I::Item) -> Option<B>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<St, F, B, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> where
+ F: FnMut(&mut St, I::Item) -> Option<B>
+{
+}
--- /dev/null
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator that skips over `n` elements of `iter`.
+///
+/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`skip`]: Iterator::skip
+/// [`Iterator`]: trait.Iterator.html
+#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Skip<I> {
+ iter: I,
+ n: usize,
+}
+
+impl<I> Skip<I> {
+ pub(in crate::iter) fn new(iter: I, n: usize) -> Skip<I> {
+ Skip { iter, n }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> Iterator for Skip<I>
+where
+ I: Iterator,
+{
+ type Item = <I as Iterator>::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<I::Item> {
+ if self.n == 0 {
+ self.iter.next()
+ } else {
+ let old_n = self.n;
+ self.n = 0;
+ self.iter.nth(old_n)
+ }
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<I::Item> {
+ // Can't just add n + self.n due to overflow.
+ if self.n > 0 {
+ let to_skip = self.n;
+ self.n = 0;
+ // nth(n) skips n+1
+ self.iter.nth(to_skip - 1)?;
+ }
+ self.iter.nth(n)
+ }
+
+ #[inline]
+ fn count(mut self) -> usize {
+ if self.n > 0 {
+ // nth(n) skips n+1
+ if self.iter.nth(self.n - 1).is_none() {
+ return 0;
+ }
+ }
+ self.iter.count()
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<I::Item> {
+ if self.n > 0 {
+ // nth(n) skips n+1
+ self.iter.nth(self.n - 1)?;
+ }
+ self.iter.last()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (lower, upper) = self.iter.size_hint();
+
+ let lower = lower.saturating_sub(self.n);
+ let upper = match upper {
+ Some(x) => Some(x.saturating_sub(self.n)),
+ None => None,
+ };
+
+ (lower, upper)
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ let n = self.n;
+ self.n = 0;
+ if n > 0 {
+ // nth(n) skips n+1
+ if self.iter.nth(n - 1).is_none() {
+ return try { init };
+ }
+ }
+ self.iter.try_fold(init, fold)
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ if self.n > 0 {
+ // nth(n) skips n+1
+ if self.iter.nth(self.n - 1).is_none() {
+ return init;
+ }
+ }
+ self.iter.fold(init, fold)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> ExactSizeIterator for Skip<I> where I: ExactSizeIterator {}
+
+#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")]
+impl<I> DoubleEndedIterator for Skip<I>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.len() > 0 { self.iter.next_back() } else { None }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<I::Item> {
+ let len = self.len();
+ if n < len {
+ self.iter.nth_back(n)
+ } else {
+ if len > 0 {
+ // consume the original iterator
+ self.iter.nth_back(len - 1);
+ }
+ None
+ }
+ }
+
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ fn check<T, Acc, R: Try<Ok = Acc>>(
+ mut n: usize,
+ mut fold: impl FnMut(Acc, T) -> R,
+ ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
+ move |acc, x| {
+ n -= 1;
+ let r = fold(acc, x);
+ if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
+ }
+ }
+
+ let n = self.len();
+ if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
+ }
+
+ fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
+ move |acc, x| Ok(f(acc, x))
+ }
+
+ self.try_rfold(init, ok(fold)).unwrap()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, I: Iterator> SourceIter for Skip<I>
+where
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {}
--- /dev/null
+use crate::fmt;
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::ops::Try;
+
+/// An iterator that rejects elements while `predicate` returns `true`.
+///
+/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`skip_while`]: Iterator::skip_while
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct SkipWhile<I, P> {
+ iter: I,
+ flag: bool,
+ predicate: P,
+}
+
+impl<I, P> SkipWhile<I, P> {
+ pub(in crate::iter) fn new(iter: I, predicate: P) -> SkipWhile<I, P> {
+ SkipWhile { iter, flag: false, predicate }
+ }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, P> fmt::Debug for SkipWhile<I, P> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SkipWhile").field("iter", &self.iter).field("flag", &self.flag).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator, P> Iterator for SkipWhile<I, P>
+where
+ P: FnMut(&I::Item) -> bool,
+{
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<I::Item> {
+ fn check<'a, T>(
+ flag: &'a mut bool,
+ pred: &'a mut impl FnMut(&T) -> bool,
+ ) -> impl FnMut(&T) -> bool + 'a {
+ move |x| {
+ if *flag || !pred(x) {
+ *flag = true;
+ true
+ } else {
+ false
+ }
+ }
+ }
+
+ let flag = &mut self.flag;
+ let pred = &mut self.predicate;
+ self.iter.find(check(flag, pred))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper) // can't know a lower bound, due to the predicate
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ if !self.flag {
+ match self.next() {
+ Some(v) => init = fold(init, v)?,
+ None => return try { init },
+ }
+ }
+ self.iter.try_fold(init, fold)
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(mut self, mut init: Acc, mut fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ if !self.flag {
+ match self.next() {
+ Some(v) => init = fold(init, v),
+ None => return init,
+ }
+ }
+ self.iter.fold(init, fold)
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I, P> FusedIterator for SkipWhile<I, P>
+where
+ I: FusedIterator,
+ P: FnMut(&I::Item) -> bool,
+{
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, P, I: Iterator> SourceIter for SkipWhile<I, P>
+where
+ P: FnMut(&I::Item) -> bool,
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> where
+ F: FnMut(&I::Item) -> bool
+{
+}
--- /dev/null
+use crate::{intrinsics, iter::from_fn, ops::Try};
+
+/// An iterator for stepping iterators by a custom amount.
+///
+/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
+/// its documentation for more.
+///
+/// [`step_by`]: Iterator::step_by
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "iterator_step_by", since = "1.28.0")]
+#[derive(Clone, Debug)]
+pub struct StepBy<I> {
+ iter: I,
+ step: usize,
+ first_take: bool,
+}
+
+impl<I> StepBy<I> {
+ pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> {
+ assert!(step != 0);
+ StepBy { iter, step: step - 1, first_take: true }
+ }
+}
+
+#[stable(feature = "iterator_step_by", since = "1.28.0")]
+impl<I> Iterator for StepBy<I>
+where
+ I: Iterator,
+{
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.first_take {
+ self.first_take = false;
+ self.iter.next()
+ } else {
+ self.iter.nth(self.step)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ #[inline]
+ fn first_size(step: usize) -> impl Fn(usize) -> usize {
+ move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) }
+ }
+
+ #[inline]
+ fn other_size(step: usize) -> impl Fn(usize) -> usize {
+ move |n| n / (step + 1)
+ }
+
+ let (low, high) = self.iter.size_hint();
+
+ if self.first_take {
+ let f = first_size(self.step);
+ (f(low), high.map(f))
+ } else {
+ let f = other_size(self.step);
+ (f(low), high.map(f))
+ }
+ }
+
+ #[inline]
+ fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
+ if self.first_take {
+ self.first_take = false;
+ let first = self.iter.next();
+ if n == 0 {
+ return first;
+ }
+ n -= 1;
+ }
+ // n and self.step are indices, we need to add 1 to get the amount of elements
+ // When calling `.nth`, we need to subtract 1 again to convert back to an index
+ // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1`
+ let mut step = self.step + 1;
+ // n + 1 could overflow
+ // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
+ if n == usize::MAX {
+ self.iter.nth(step - 1);
+ } else {
+ n += 1;
+ }
+
+ // overflow handling
+ loop {
+ let mul = n.checked_mul(step);
+ {
+ if intrinsics::likely(mul.is_some()) {
+ return self.iter.nth(mul.unwrap() - 1);
+ }
+ }
+ let div_n = usize::MAX / n;
+ let div_step = usize::MAX / step;
+ let nth_n = div_n * n;
+ let nth_step = div_step * step;
+ let nth = if nth_n > nth_step {
+ step -= div_n;
+ nth_n
+ } else {
+ n -= div_step;
+ nth_step
+ };
+ self.iter.nth(nth - 1);
+ }
+ }
+
+ fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
+ where
+ F: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ #[inline]
+ fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
+ move || iter.nth(step)
+ }
+
+ if self.first_take {
+ self.first_take = false;
+ match self.iter.next() {
+ None => return try { acc },
+ Some(x) => acc = f(acc, x)?,
+ }
+ }
+ from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f)
+ }
+
+ fn fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
+ where
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
+ move || iter.nth(step)
+ }
+
+ if self.first_take {
+ self.first_take = false;
+ match self.iter.next() {
+ None => return acc,
+ Some(x) => acc = f(acc, x),
+ }
+ }
+ from_fn(nth(&mut self.iter, self.step)).fold(acc, f)
+ }
+}
+
+impl<I> StepBy<I>
+where
+ I: ExactSizeIterator,
+{
+ // The zero-based index starting from the end of the iterator of the
+ // last element. Used in the `DoubleEndedIterator` implementation.
+ fn next_back_index(&self) -> usize {
+ let rem = self.iter.len() % (self.step + 1);
+ if self.first_take {
+ if rem == 0 { self.step } else { rem - 1 }
+ } else {
+ rem
+ }
+ }
+}
+
+#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
+impl<I> DoubleEndedIterator for StepBy<I>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.iter.nth_back(self.next_back_index())
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ // `self.iter.nth_back(usize::MAX)` does the right thing here when `n`
+ // is out of bounds because the length of `self.iter` does not exceed
+ // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
+ // zero-indexed
+ let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index());
+ self.iter.nth_back(n)
+ }
+
+ fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
+ where
+ F: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ #[inline]
+ fn nth_back<I: DoubleEndedIterator>(
+ iter: &mut I,
+ step: usize,
+ ) -> impl FnMut() -> Option<I::Item> + '_ {
+ move || iter.nth_back(step)
+ }
+
+ match self.next_back() {
+ None => try { init },
+ Some(x) => {
+ let acc = f(init, x)?;
+ from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f)
+ }
+ }
+ }
+
+ #[inline]
+ fn rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
+ where
+ Self: Sized,
+ F: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn nth_back<I: DoubleEndedIterator>(
+ iter: &mut I,
+ step: usize,
+ ) -> impl FnMut() -> Option<I::Item> + '_ {
+ move || iter.nth_back(step)
+ }
+
+ match self.next_back() {
+ None => init,
+ Some(x) => {
+ let acc = f(init, x);
+ from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f)
+ }
+ }
+ }
+}
+
+// StepBy can only make the iterator shorter, so the len will still fit.
+#[stable(feature = "iterator_step_by", since = "1.28.0")]
+impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
--- /dev/null
+use crate::cmp;
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator that only iterates over the first `n` iterations of `iter`.
+///
+/// This `struct` is created by the [`take`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`take`]: Iterator::take
+/// [`Iterator`]: trait.Iterator.html
+#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Take<I> {
+ iter: I,
+ n: usize,
+}
+
+impl<I> Take<I> {
+ pub(in crate::iter) fn new(iter: I, n: usize) -> Take<I> {
+ Take { iter, n }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> Iterator for Take<I>
+where
+ I: Iterator,
+{
+ type Item = <I as Iterator>::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<<I as Iterator>::Item> {
+ if self.n != 0 {
+ self.n -= 1;
+ self.iter.next()
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<I::Item> {
+ if self.n > n {
+ self.n -= n + 1;
+ self.iter.nth(n)
+ } else {
+ if self.n > 0 {
+ self.iter.nth(self.n - 1);
+ self.n = 0;
+ }
+ None
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.n == 0 {
+ return (0, Some(0));
+ }
+
+ let (lower, upper) = self.iter.size_hint();
+
+ let lower = cmp::min(lower, self.n);
+
+ let upper = match upper {
+ Some(x) if x < self.n => Some(x),
+ _ => Some(self.n),
+ };
+
+ (lower, upper)
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ fn check<'a, T, Acc, R: Try<Ok = Acc>>(
+ n: &'a mut usize,
+ mut fold: impl FnMut(Acc, T) -> R + 'a,
+ ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
+ move |acc, x| {
+ *n -= 1;
+ let r = fold(acc, x);
+ if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
+ }
+ }
+
+ if self.n == 0 {
+ try { init }
+ } else {
+ let n = &mut self.n;
+ self.iter.try_fold(init, check(n, fold)).into_try()
+ }
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
+ move |acc, x| Ok(f(acc, x))
+ }
+
+ self.try_fold(init, ok(fold)).unwrap()
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, I: Iterator> SourceIter for Take<I>
+where
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> {}
+
+#[stable(feature = "double_ended_take_iterator", since = "1.38.0")]
+impl<I> DoubleEndedIterator for Take<I>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.n == 0 {
+ None
+ } else {
+ let n = self.n;
+ self.n -= 1;
+ self.iter.nth_back(self.iter.len().saturating_sub(n))
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.iter.len();
+ if self.n > n {
+ let m = len.saturating_sub(self.n) + n;
+ self.n -= n + 1;
+ self.iter.nth_back(m)
+ } else {
+ if len > 0 {
+ self.iter.nth_back(len - 1);
+ }
+ None
+ }
+ }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ if self.n == 0 {
+ try { init }
+ } else {
+ let len = self.iter.len();
+ if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
+ try { init }
+ } else {
+ self.iter.try_rfold(init, fold)
+ }
+ }
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ if self.n == 0 {
+ init
+ } else {
+ let len = self.iter.len();
+ if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
+ init
+ } else {
+ self.iter.rfold(init, fold)
+ }
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I> FusedIterator for Take<I> where I: FusedIterator {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
--- /dev/null
+use crate::fmt;
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator that only accepts elements while `predicate` returns `true`.
+///
+/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`take_while`]: Iterator::take_while
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct TakeWhile<I, P> {
+ iter: I,
+ flag: bool,
+ predicate: P,
+}
+
+impl<I, P> TakeWhile<I, P> {
+ pub(in crate::iter) fn new(iter: I, predicate: P) -> TakeWhile<I, P> {
+ TakeWhile { iter, flag: false, predicate }
+ }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, P> fmt::Debug for TakeWhile<I, P> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("TakeWhile").field("iter", &self.iter).field("flag", &self.flag).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator, P> Iterator for TakeWhile<I, P>
+where
+ P: FnMut(&I::Item) -> bool,
+{
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<I::Item> {
+ if self.flag {
+ None
+ } else {
+ let x = self.iter.next()?;
+ if (self.predicate)(&x) {
+ Some(x)
+ } else {
+ self.flag = true;
+ None
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.flag {
+ (0, Some(0))
+ } else {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper) // can't know a lower bound, due to the predicate
+ }
+ }
+
+ #[inline]
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Ok = Acc>,
+ {
+ fn check<'a, T, Acc, R: Try<Ok = Acc>>(
+ flag: &'a mut bool,
+ p: &'a mut impl FnMut(&T) -> bool,
+ mut fold: impl FnMut(Acc, T) -> R + 'a,
+ ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
+ move |acc, x| {
+ if p(&x) {
+ ControlFlow::from_try(fold(acc, x))
+ } else {
+ *flag = true;
+ ControlFlow::Break(try { acc })
+ }
+ }
+ }
+
+ if self.flag {
+ try { init }
+ } else {
+ let flag = &mut self.flag;
+ let p = &mut self.predicate;
+ self.iter.try_fold(init, check(flag, p, fold)).into_try()
+ }
+ }
+
+ #[inline]
+ fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ #[inline]
+ fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
+ move |acc, x| Ok(f(acc, x))
+ }
+
+ self.try_fold(init, ok(fold)).unwrap()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I, P> FusedIterator for TakeWhile<I, P>
+where
+ I: FusedIterator,
+ P: FnMut(&I::Item) -> bool,
+{
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<S: Iterator, P, I: Iterator> SourceIter for TakeWhile<I, P>
+where
+ P: FnMut(&I::Item) -> bool,
+ I: SourceIter<Source = S>,
+{
+ type Source = S;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut S {
+ // SAFETY: unsafe function forwarding to unsafe function with the same requirements
+ unsafe { SourceIter::as_inner(&mut self.iter) }
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> where
+ F: FnMut(&I::Item) -> bool
+{
+}
use crate::cmp;
use crate::fmt::{self, Debug};
-
-use super::super::{
- DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, SourceIter,
- TrustedLen,
-};
+use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
+use crate::iter::{InPlaceIterable, SourceIter, TrustedLen};
/// An iterator that iterates two other iterators simultaneously.
///
len: usize,
}
impl<A: Iterator, B: Iterator> Zip<A, B> {
- pub(in super::super) fn new(a: A, b: B) -> Zip<A, B> {
+ pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
ZipImpl::new(a, b)
}
fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> {
#[stable(feature = "fused", since = "1.26.0")]
pub use self::traits::FusedIterator;
+#[unstable(issue = "none", feature = "inplace_iteration")]
+pub use self::traits::InPlaceIterable;
#[unstable(feature = "trusted_len", issue = "37572")]
pub use self::traits::TrustedLen;
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::traits::{DoubleEndedIterator, Extend, FromIterator, IntoIterator};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::traits::{ExactSizeIterator, Product, Sum};
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-pub use self::traits::InPlaceIterable;
+pub use self::traits::{
+ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,
+};
#[stable(feature = "iter_cloned", since = "1.1.0")]
pub use self::adapters::Cloned;
pub use self::adapters::Copied;
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub use self::adapters::Flatten;
-
#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
pub use self::adapters::MapWhile;
-#[unstable(issue = "none", feature = "inplace_iteration")]
+#[unstable(feature = "inplace_iteration", issue = "none")]
pub use self::adapters::SourceIter;
#[stable(feature = "iterator_step_by", since = "1.28.0")]
pub use self::adapters::StepBy;
#[unstable(feature = "trusted_random_access", issue = "none")]
pub use self::adapters::TrustedRandomAccess;
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::adapters::{Chain, Cycle, Enumerate, Filter, FilterMap, Map, Rev, Zip};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::adapters::{FlatMap, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::adapters::{Fuse, Inspect};
+pub use self::adapters::{
+ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan,
+ Skip, SkipWhile, Take, TakeWhile, Zip,
+};
pub(crate) use self::adapters::process_results;
-use crate::fmt;
-use crate::marker;
+mod empty;
+mod from_fn;
+mod once;
+mod once_with;
+mod repeat;
+mod repeat_with;
+mod successors;
-use super::{FusedIterator, TrustedLen};
+pub use self::repeat::{repeat, Repeat};
-/// An iterator that repeats an element endlessly.
-///
-/// This `struct` is created by the [`repeat()`] function. See its documentation for more.
-#[derive(Clone, Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Repeat<A> {
- element: A,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Clone> Iterator for Repeat<A> {
- type Item = A;
-
- #[inline]
- fn next(&mut self) -> Option<A> {
- Some(self.element.clone())
- }
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- (usize::MAX, None)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Clone> DoubleEndedIterator for Repeat<A> {
- #[inline]
- fn next_back(&mut self) -> Option<A> {
- Some(self.element.clone())
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<A: Clone> FusedIterator for Repeat<A> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
-
-/// Creates a new iterator that endlessly repeats a single element.
-///
-/// The `repeat()` function repeats a single value over and over again.
-///
-/// Infinite iterators like `repeat()` are often used with adapters like
-/// [`Iterator::take()`], in order to make them finite.
-///
-/// If the element type of the iterator you need does not implement `Clone`,
-/// or if you do not want to keep the repeated element in memory, you can
-/// instead use the [`repeat_with()`] function.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::iter;
-///
-/// // the number four 4ever:
-/// let mut fours = iter::repeat(4);
-///
-/// assert_eq!(Some(4), fours.next());
-/// assert_eq!(Some(4), fours.next());
-/// assert_eq!(Some(4), fours.next());
-/// assert_eq!(Some(4), fours.next());
-/// assert_eq!(Some(4), fours.next());
-///
-/// // yup, still four
-/// assert_eq!(Some(4), fours.next());
-/// ```
-///
-/// Going finite with [`Iterator::take()`]:
-///
-/// ```
-/// use std::iter;
-///
-/// // that last example was too many fours. Let's only have four fours.
-/// let mut four_fours = iter::repeat(4).take(4);
-///
-/// assert_eq!(Some(4), four_fours.next());
-/// assert_eq!(Some(4), four_fours.next());
-/// assert_eq!(Some(4), four_fours.next());
-/// assert_eq!(Some(4), four_fours.next());
-///
-/// // ... and now we're done
-/// assert_eq!(None, four_fours.next());
-/// ```
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
- Repeat { element: elt }
-}
-
-/// An iterator that repeats elements of type `A` endlessly by
-/// applying the provided closure `F: FnMut() -> A`.
-///
-/// This `struct` is created by the [`repeat_with()`] function.
-/// See its documentation for more.
-#[derive(Copy, Clone, Debug)]
-#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
-pub struct RepeatWith<F> {
- repeater: F,
-}
-
-#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
-impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
- type Item = A;
-
- #[inline]
- fn next(&mut self) -> Option<A> {
- Some((self.repeater)())
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- (usize::MAX, None)
- }
-}
-
-#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
-impl<A, F: FnMut() -> A> FusedIterator for RepeatWith<F> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {}
-
-/// Creates a new iterator that repeats elements of type `A` endlessly by
-/// applying the provided closure, the repeater, `F: FnMut() -> A`.
-///
-/// The `repeat_with()` function calls the repeater over and over again.
-///
-/// Infinite iterators like `repeat_with()` are often used with adapters like
-/// [`Iterator::take()`], in order to make them finite.
-///
-/// If the element type of the iterator you need implements [`Clone`], and
-/// it is OK to keep the source element in memory, you should instead use
-/// the [`repeat()`] function.
-///
-/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`].
-/// If you need `repeat_with()` to return a [`DoubleEndedIterator`],
-/// please open a GitHub issue explaining your use case.
-///
-/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::iter;
-///
-/// // let's assume we have some value of a type that is not `Clone`
-/// // or which don't want to have in memory just yet because it is expensive:
-/// #[derive(PartialEq, Debug)]
-/// struct Expensive;
-///
-/// // a particular value forever:
-/// let mut things = iter::repeat_with(|| Expensive);
-///
-/// assert_eq!(Some(Expensive), things.next());
-/// assert_eq!(Some(Expensive), things.next());
-/// assert_eq!(Some(Expensive), things.next());
-/// assert_eq!(Some(Expensive), things.next());
-/// assert_eq!(Some(Expensive), things.next());
-/// ```
-///
-/// Using mutation and going finite:
-///
-/// ```rust
-/// use std::iter;
-///
-/// // From the zeroth to the third power of two:
-/// let mut curr = 1;
-/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp })
-/// .take(4);
-///
-/// assert_eq!(Some(1), pow2.next());
-/// assert_eq!(Some(2), pow2.next());
-/// assert_eq!(Some(4), pow2.next());
-/// assert_eq!(Some(8), pow2.next());
-///
-/// // ... and now we're done
-/// assert_eq!(None, pow2.next());
-/// ```
-#[inline]
-#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
-pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
- RepeatWith { repeater }
-}
-
-/// An iterator that yields nothing.
-///
-/// This `struct` is created by the [`empty()`] function. See its documentation for more.
#[stable(feature = "iter_empty", since = "1.2.0")]
-pub struct Empty<T>(marker::PhantomData<T>);
-
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Send for Empty<T> {}
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Sync for Empty<T> {}
+pub use self::empty::{empty, Empty};
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T> fmt::Debug for Empty<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad("Empty")
- }
-}
-
-#[stable(feature = "iter_empty", since = "1.2.0")]
-impl<T> Iterator for Empty<T> {
- type Item = T;
-
- fn next(&mut self) -> Option<T> {
- None
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- (0, Some(0))
- }
-}
-
-#[stable(feature = "iter_empty", since = "1.2.0")]
-impl<T> DoubleEndedIterator for Empty<T> {
- fn next_back(&mut self) -> Option<T> {
- None
- }
-}
-
-#[stable(feature = "iter_empty", since = "1.2.0")]
-impl<T> ExactSizeIterator for Empty<T> {
- fn len(&self) -> usize {
- 0
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for Empty<T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Empty<T> {}
-
-// not #[derive] because that adds a Clone bound on T,
-// which isn't necessary.
-#[stable(feature = "iter_empty", since = "1.2.0")]
-impl<T> Clone for Empty<T> {
- fn clone(&self) -> Empty<T> {
- Empty(marker::PhantomData)
- }
-}
-
-// not #[derive] because that adds a Default bound on T,
-// which isn't necessary.
-#[stable(feature = "iter_empty", since = "1.2.0")]
-impl<T> Default for Empty<T> {
- fn default() -> Empty<T> {
- Empty(marker::PhantomData)
- }
-}
-
-/// Creates an iterator that yields nothing.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::iter;
-///
-/// // this could have been an iterator over i32, but alas, it's just not.
-/// let mut nope = iter::empty::<i32>();
-///
-/// assert_eq!(None, nope.next());
-/// ```
-#[stable(feature = "iter_empty", since = "1.2.0")]
-#[rustc_const_stable(feature = "const_iter_empty", since = "1.32.0")]
-pub const fn empty<T>() -> Empty<T> {
- Empty(marker::PhantomData)
-}
-
-/// An iterator that yields an element exactly once.
-///
-/// This `struct` is created by the [`once()`] function. See its documentation for more.
-#[derive(Clone, Debug)]
#[stable(feature = "iter_once", since = "1.2.0")]
-pub struct Once<T> {
- inner: crate::option::IntoIter<T>,
-}
+pub use self::once::{once, Once};
-#[stable(feature = "iter_once", since = "1.2.0")]
-impl<T> Iterator for Once<T> {
- type Item = T;
-
- fn next(&mut self) -> Option<T> {
- self.inner.next()
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
- }
-}
-
-#[stable(feature = "iter_once", since = "1.2.0")]
-impl<T> DoubleEndedIterator for Once<T> {
- fn next_back(&mut self) -> Option<T> {
- self.inner.next_back()
- }
-}
-
-#[stable(feature = "iter_once", since = "1.2.0")]
-impl<T> ExactSizeIterator for Once<T> {
- fn len(&self) -> usize {
- self.inner.len()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for Once<T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Once<T> {}
-
-/// Creates an iterator that yields an element exactly once.
-///
-/// This is commonly used to adapt a single value into a [`chain()`] of other
-/// kinds of iteration. Maybe you have an iterator that covers almost
-/// everything, but you need an extra special case. Maybe you have a function
-/// which works on iterators, but you only need to process one value.
-///
-/// [`chain()`]: Iterator::chain
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::iter;
-///
-/// // one is the loneliest number
-/// let mut one = iter::once(1);
-///
-/// assert_eq!(Some(1), one.next());
-///
-/// // just one, that's all we get
-/// assert_eq!(None, one.next());
-/// ```
-///
-/// Chaining together with another iterator. Let's say that we want to iterate
-/// over each file of the `.foo` directory, but also a configuration file,
-/// `.foorc`:
-///
-/// ```no_run
-/// use std::iter;
-/// use std::fs;
-/// use std::path::PathBuf;
-///
-/// let dirs = fs::read_dir(".foo").unwrap();
-///
-/// // we need to convert from an iterator of DirEntry-s to an iterator of
-/// // PathBufs, so we use map
-/// let dirs = dirs.map(|file| file.unwrap().path());
-///
-/// // now, our iterator just for our config file
-/// let config = iter::once(PathBuf::from(".foorc"));
-///
-/// // chain the two iterators together into one big iterator
-/// let files = dirs.chain(config);
-///
-/// // this will give us all of the files in .foo as well as .foorc
-/// for f in files {
-/// println!("{:?}", f);
-/// }
-/// ```
-#[stable(feature = "iter_once", since = "1.2.0")]
-pub fn once<T>(value: T) -> Once<T> {
- Once { inner: Some(value).into_iter() }
-}
-
-/// An iterator that yields a single element of type `A` by
-/// applying the provided closure `F: FnOnce() -> A`.
-///
-/// This `struct` is created by the [`once_with()`] function.
-/// See its documentation for more.
-#[derive(Clone, Debug)]
-#[stable(feature = "iter_once_with", since = "1.43.0")]
-pub struct OnceWith<F> {
- gen: Option<F>,
-}
-
-#[stable(feature = "iter_once_with", since = "1.43.0")]
-impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> {
- type Item = A;
-
- #[inline]
- fn next(&mut self) -> Option<A> {
- let f = self.gen.take()?;
- Some(f())
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.gen.iter().size_hint()
- }
-}
-
-#[stable(feature = "iter_once_with", since = "1.43.0")]
-impl<A, F: FnOnce() -> A> DoubleEndedIterator for OnceWith<F> {
- fn next_back(&mut self) -> Option<A> {
- self.next()
- }
-}
-
-#[stable(feature = "iter_once_with", since = "1.43.0")]
-impl<A, F: FnOnce() -> A> ExactSizeIterator for OnceWith<F> {
- fn len(&self) -> usize {
- self.gen.iter().len()
- }
-}
-
-#[stable(feature = "iter_once_with", since = "1.43.0")]
-impl<A, F: FnOnce() -> A> FusedIterator for OnceWith<F> {}
-
-#[stable(feature = "iter_once_with", since = "1.43.0")]
-unsafe impl<A, F: FnOnce() -> A> TrustedLen for OnceWith<F> {}
-
-/// Creates an iterator that lazily generates a value exactly once by invoking
-/// the provided closure.
-///
-/// This is commonly used to adapt a single value generator into a [`chain()`] of
-/// other kinds of iteration. Maybe you have an iterator that covers almost
-/// everything, but you need an extra special case. Maybe you have a function
-/// which works on iterators, but you only need to process one value.
-///
-/// Unlike [`once()`], this function will lazily generate the value on request.
-///
-/// [`chain()`]: Iterator::chain
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::iter;
-///
-/// // one is the loneliest number
-/// let mut one = iter::once_with(|| 1);
-///
-/// assert_eq!(Some(1), one.next());
-///
-/// // just one, that's all we get
-/// assert_eq!(None, one.next());
-/// ```
-///
-/// Chaining together with another iterator. Let's say that we want to iterate
-/// over each file of the `.foo` directory, but also a configuration file,
-/// `.foorc`:
-///
-/// ```no_run
-/// use std::iter;
-/// use std::fs;
-/// use std::path::PathBuf;
-///
-/// let dirs = fs::read_dir(".foo").unwrap();
-///
-/// // we need to convert from an iterator of DirEntry-s to an iterator of
-/// // PathBufs, so we use map
-/// let dirs = dirs.map(|file| file.unwrap().path());
-///
-/// // now, our iterator just for our config file
-/// let config = iter::once_with(|| PathBuf::from(".foorc"));
-///
-/// // chain the two iterators together into one big iterator
-/// let files = dirs.chain(config);
-///
-/// // this will give us all of the files in .foo as well as .foorc
-/// for f in files {
-/// println!("{:?}", f);
-/// }
-/// ```
-#[inline]
-#[stable(feature = "iter_once_with", since = "1.43.0")]
-pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
- OnceWith { gen: Some(gen) }
-}
-
-/// Creates a new iterator where each iteration calls the provided closure
-/// `F: FnMut() -> Option<T>`.
-///
-/// This allows creating a custom iterator with any behavior
-/// without using the more verbose syntax of creating a dedicated type
-/// and implementing the [`Iterator`] trait for it.
-///
-/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure,
-/// and therefore conservatively does not implement [`FusedIterator`],
-/// or override [`Iterator::size_hint()`] from its default `(0, None)`.
-///
-/// The closure can use captures and its environment to track state across iterations. Depending on
-/// how the iterator is used, this may require specifying the [`move`] keyword on the closure.
-///
-/// [`move`]: ../../std/keyword.move.html
-///
-/// # Examples
-///
-/// Let’s re-implement the counter iterator from the [module-level documentation]:
-///
-/// [module-level documentation]: super
-///
-/// ```
-/// let mut count = 0;
-/// let counter = std::iter::from_fn(move || {
-/// // Increment our count. This is why we started at zero.
-/// count += 1;
-///
-/// // Check to see if we've finished counting or not.
-/// if count < 6 {
-/// Some(count)
-/// } else {
-/// None
-/// }
-/// });
-/// assert_eq!(counter.collect::<Vec<_>>(), &[1, 2, 3, 4, 5]);
-/// ```
-#[inline]
-#[stable(feature = "iter_from_fn", since = "1.34.0")]
-pub fn from_fn<T, F>(f: F) -> FromFn<F>
-where
- F: FnMut() -> Option<T>,
-{
- FromFn(f)
-}
-
-/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option<T>`.
-///
-/// This `struct` is created by the [`iter::from_fn()`] function.
-/// See its documentation for more.
-///
-/// [`iter::from_fn()`]: from_fn
-#[derive(Clone)]
-#[stable(feature = "iter_from_fn", since = "1.34.0")]
-pub struct FromFn<F>(F);
-
-#[stable(feature = "iter_from_fn", since = "1.34.0")]
-impl<T, F> Iterator for FromFn<F>
-where
- F: FnMut() -> Option<T>,
-{
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<Self::Item> {
- (self.0)()
- }
-}
+#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
+pub use self::repeat_with::{repeat_with, RepeatWith};
#[stable(feature = "iter_from_fn", since = "1.34.0")]
-impl<F> fmt::Debug for FromFn<F> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("FromFn").finish()
- }
-}
+pub use self::from_fn::{from_fn, FromFn};
-/// Creates a new iterator where each successive item is computed based on the preceding one.
-///
-/// The iterator starts with the given first item (if any)
-/// and calls the given `FnMut(&T) -> Option<T>` closure to compute each item’s successor.
-///
-/// ```
-/// use std::iter::successors;
-///
-/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
-/// assert_eq!(powers_of_10.collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
-/// ```
#[stable(feature = "iter_successors", since = "1.34.0")]
-pub fn successors<T, F>(first: Option<T>, succ: F) -> Successors<T, F>
-where
- F: FnMut(&T) -> Option<T>,
-{
- // If this function returned `impl Iterator<Item=T>`
- // it could be based on `unfold` and not need a dedicated type.
- // However having a named `Successors<T, F>` type allows it to be `Clone` when `T` and `F` are.
- Successors { next: first, succ }
-}
+pub use self::successors::{successors, Successors};
-/// An new iterator where each successive item is computed based on the preceding one.
-///
-/// This `struct` is created by the [`iter::successors()`] function.
-/// See its documentation for more.
-///
-/// [`iter::successors()`]: successors
-#[derive(Clone)]
-#[stable(feature = "iter_successors", since = "1.34.0")]
-pub struct Successors<T, F> {
- next: Option<T>,
- succ: F,
-}
-
-#[stable(feature = "iter_successors", since = "1.34.0")]
-impl<T, F> Iterator for Successors<T, F>
-where
- F: FnMut(&T) -> Option<T>,
-{
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<Self::Item> {
- let item = self.next.take()?;
- self.next = (self.succ)(&item);
- Some(item)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.next.is_some() { (1, None) } else { (0, Some(0)) }
- }
-}
-
-#[stable(feature = "iter_successors", since = "1.34.0")]
-impl<T, F> FusedIterator for Successors<T, F> where F: FnMut(&T) -> Option<T> {}
-
-#[stable(feature = "iter_successors", since = "1.34.0")]
-impl<T: fmt::Debug, F> fmt::Debug for Successors<T, F> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Successors").field("next", &self.next).finish()
- }
-}
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+pub use self::once_with::{once_with, OnceWith};
--- /dev/null
+use crate::fmt;
+use crate::iter::{FusedIterator, TrustedLen};
+use crate::marker;
+
+/// Creates an iterator that yields nothing.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // this could have been an iterator over i32, but alas, it's just not.
+/// let mut nope = iter::empty::<i32>();
+///
+/// assert_eq!(None, nope.next());
+/// ```
+#[stable(feature = "iter_empty", since = "1.2.0")]
+#[rustc_const_stable(feature = "const_iter_empty", since = "1.32.0")]
+pub const fn empty<T>() -> Empty<T> {
+ Empty(marker::PhantomData)
+}
+
+/// An iterator that yields nothing.
+///
+/// This `struct` is created by the [`empty()`] function. See its documentation for more.
+#[stable(feature = "iter_empty", since = "1.2.0")]
+pub struct Empty<T>(marker::PhantomData<T>);
+
+#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
+unsafe impl<T> Send for Empty<T> {}
+#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
+unsafe impl<T> Sync for Empty<T> {}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T> fmt::Debug for Empty<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Empty")
+ }
+}
+
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> Iterator for Empty<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ None
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(0))
+ }
+}
+
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> DoubleEndedIterator for Empty<T> {
+ fn next_back(&mut self) -> Option<T> {
+ None
+ }
+}
+
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> ExactSizeIterator for Empty<T> {
+ fn len(&self) -> usize {
+ 0
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for Empty<T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Empty<T> {}
+
+// not #[derive] because that adds a Clone bound on T,
+// which isn't necessary.
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> Clone for Empty<T> {
+ fn clone(&self) -> Empty<T> {
+ Empty(marker::PhantomData)
+ }
+}
+
+// not #[derive] because that adds a Default bound on T,
+// which isn't necessary.
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> Default for Empty<T> {
+ fn default() -> Empty<T> {
+ Empty(marker::PhantomData)
+ }
+}
--- /dev/null
+use crate::fmt;
+
+/// Creates a new iterator where each iteration calls the provided closure
+/// `F: FnMut() -> Option<T>`.
+///
+/// This allows creating a custom iterator with any behavior
+/// without using the more verbose syntax of creating a dedicated type
+/// and implementing the [`Iterator`] trait for it.
+///
+/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure,
+/// and therefore conservatively does not implement [`FusedIterator`],
+/// or override [`Iterator::size_hint()`] from its default `(0, None)`.
+///
+/// The closure can use captures and its environment to track state across iterations. Depending on
+/// how the iterator is used, this may require specifying the [`move`] keyword on the closure.
+///
+/// [`move`]: ../../std/keyword.move.html
+/// [`FusedIterator`]: crate::iter::FusedIterator
+///
+/// # Examples
+///
+/// Let’s re-implement the counter iterator from [module-level documentation]:
+///
+/// [module-level documentation]: crate::iter
+///
+/// ```
+/// let mut count = 0;
+/// let counter = std::iter::from_fn(move || {
+/// // Increment our count. This is why we started at zero.
+/// count += 1;
+///
+/// // Check to see if we've finished counting or not.
+/// if count < 6 {
+/// Some(count)
+/// } else {
+/// None
+/// }
+/// });
+/// assert_eq!(counter.collect::<Vec<_>>(), &[1, 2, 3, 4, 5]);
+/// ```
+#[inline]
+#[stable(feature = "iter_from_fn", since = "1.34.0")]
+pub fn from_fn<T, F>(f: F) -> FromFn<F>
+where
+ F: FnMut() -> Option<T>,
+{
+ FromFn(f)
+}
+
+/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option<T>`.
+///
+/// This `struct` is created by the [`iter::from_fn()`] function.
+/// See its documentation for more.
+///
+/// [`iter::from_fn()`]: from_fn
+#[derive(Clone)]
+#[stable(feature = "iter_from_fn", since = "1.34.0")]
+pub struct FromFn<F>(F);
+
+#[stable(feature = "iter_from_fn", since = "1.34.0")]
+impl<T, F> Iterator for FromFn<F>
+where
+ F: FnMut() -> Option<T>,
+{
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ (self.0)()
+ }
+}
+
+#[stable(feature = "iter_from_fn", since = "1.34.0")]
+impl<F> fmt::Debug for FromFn<F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FromFn").finish()
+ }
+}
--- /dev/null
+use crate::iter::{FusedIterator, TrustedLen};
+
+/// Creates an iterator that yields an element exactly once.
+///
+/// This is commonly used to adapt a single value into a [`chain()`] of other
+/// kinds of iteration. Maybe you have an iterator that covers almost
+/// everything, but you need an extra special case. Maybe you have a function
+/// which works on iterators, but you only need to process one value.
+///
+/// [`chain()`]: Iterator::chain
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // one is the loneliest number
+/// let mut one = iter::once(1);
+///
+/// assert_eq!(Some(1), one.next());
+///
+/// // just one, that's all we get
+/// assert_eq!(None, one.next());
+/// ```
+///
+/// Chaining together with another iterator. Let's say that we want to iterate
+/// over each file of the `.foo` directory, but also a configuration file,
+/// `.foorc`:
+///
+/// ```no_run
+/// use std::iter;
+/// use std::fs;
+/// use std::path::PathBuf;
+///
+/// let dirs = fs::read_dir(".foo").unwrap();
+///
+/// // we need to convert from an iterator of DirEntry-s to an iterator of
+/// // PathBufs, so we use map
+/// let dirs = dirs.map(|file| file.unwrap().path());
+///
+/// // now, our iterator just for our config file
+/// let config = iter::once(PathBuf::from(".foorc"));
+///
+/// // chain the two iterators together into one big iterator
+/// let files = dirs.chain(config);
+///
+/// // this will give us all of the files in .foo as well as .foorc
+/// for f in files {
+/// println!("{:?}", f);
+/// }
+/// ```
+#[stable(feature = "iter_once", since = "1.2.0")]
+pub fn once<T>(value: T) -> Once<T> {
+ Once { inner: Some(value).into_iter() }
+}
+
+/// An iterator that yields an element exactly once.
+///
+/// This `struct` is created by the [`once()`] function. See its documentation for more.
+#[derive(Clone, Debug)]
+#[stable(feature = "iter_once", since = "1.2.0")]
+pub struct Once<T> {
+ inner: crate::option::IntoIter<T>,
+}
+
+#[stable(feature = "iter_once", since = "1.2.0")]
+impl<T> Iterator for Once<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ self.inner.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+#[stable(feature = "iter_once", since = "1.2.0")]
+impl<T> DoubleEndedIterator for Once<T> {
+ fn next_back(&mut self) -> Option<T> {
+ self.inner.next_back()
+ }
+}
+
+#[stable(feature = "iter_once", since = "1.2.0")]
+impl<T> ExactSizeIterator for Once<T> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for Once<T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Once<T> {}
--- /dev/null
+use crate::iter::{FusedIterator, TrustedLen};
+
+/// Creates an iterator that lazily generates a value exactly once by invoking
+/// the provided closure.
+///
+/// This is commonly used to adapt a single value generator into a [`chain()`] of
+/// other kinds of iteration. Maybe you have an iterator that covers almost
+/// everything, but you need an extra special case. Maybe you have a function
+/// which works on iterators, but you only need to process one value.
+///
+/// Unlike [`once()`], this function will lazily generate the value on request.
+///
+/// [`chain()`]: Iterator::chain
+/// [`once()`]: crate::iter::once
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // one is the loneliest number
+/// let mut one = iter::once_with(|| 1);
+///
+/// assert_eq!(Some(1), one.next());
+///
+/// // just one, that's all we get
+/// assert_eq!(None, one.next());
+/// ```
+///
+/// Chaining together with another iterator. Let's say that we want to iterate
+/// over each file of the `.foo` directory, but also a configuration file,
+/// `.foorc`:
+///
+/// ```no_run
+/// use std::iter;
+/// use std::fs;
+/// use std::path::PathBuf;
+///
+/// let dirs = fs::read_dir(".foo").unwrap();
+///
+/// // we need to convert from an iterator of DirEntry-s to an iterator of
+/// // PathBufs, so we use map
+/// let dirs = dirs.map(|file| file.unwrap().path());
+///
+/// // now, our iterator just for our config file
+/// let config = iter::once_with(|| PathBuf::from(".foorc"));
+///
+/// // chain the two iterators together into one big iterator
+/// let files = dirs.chain(config);
+///
+/// // this will give us all of the files in .foo as well as .foorc
+/// for f in files {
+/// println!("{:?}", f);
+/// }
+/// ```
+#[inline]
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
+ OnceWith { gen: Some(gen) }
+}
+
+/// An iterator that yields a single element of type `A` by
+/// applying the provided closure `F: FnOnce() -> A`.
+///
+/// This `struct` is created by the [`once_with()`] function.
+/// See its documentation for more.
+#[derive(Clone, Debug)]
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+pub struct OnceWith<F> {
+ gen: Option<F>,
+}
+
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ let f = self.gen.take()?;
+ Some(f())
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.gen.iter().size_hint()
+ }
+}
+
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+impl<A, F: FnOnce() -> A> DoubleEndedIterator for OnceWith<F> {
+ fn next_back(&mut self) -> Option<A> {
+ self.next()
+ }
+}
+
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+impl<A, F: FnOnce() -> A> ExactSizeIterator for OnceWith<F> {
+ fn len(&self) -> usize {
+ self.gen.iter().len()
+ }
+}
+
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+impl<A, F: FnOnce() -> A> FusedIterator for OnceWith<F> {}
+
+#[stable(feature = "iter_once_with", since = "1.43.0")]
+unsafe impl<A, F: FnOnce() -> A> TrustedLen for OnceWith<F> {}
--- /dev/null
+use crate::iter::{FusedIterator, TrustedLen};
+
+/// Creates a new iterator that endlessly repeats a single element.
+///
+/// The `repeat()` function repeats a single value over and over again.
+///
+/// Infinite iterators like `repeat()` are often used with adapters like
+/// [`Iterator::take()`], in order to make them finite.
+///
+/// If the element type of the iterator you need does not implement `Clone`,
+/// or if you do not want to keep the repeated element in memory, you can
+/// instead use the [`repeat_with()`] function.
+///
+/// [`repeat_with()`]: crate::iter::repeat_with
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // the number four 4ever:
+/// let mut fours = iter::repeat(4);
+///
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+///
+/// // yup, still four
+/// assert_eq!(Some(4), fours.next());
+/// ```
+///
+/// Going finite with [`Iterator::take()`]:
+///
+/// ```
+/// use std::iter;
+///
+/// // that last example was too many fours. Let's only have four fours.
+/// let mut four_fours = iter::repeat(4).take(4);
+///
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+///
+/// // ... and now we're done
+/// assert_eq!(None, four_fours.next());
+/// ```
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
+ Repeat { element: elt }
+}
+
+/// An iterator that repeats an element endlessly.
+///
+/// This `struct` is created by the [`repeat()`] function. See its documentation for more.
+#[derive(Clone, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Repeat<A> {
+ element: A,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Clone> Iterator for Repeat<A> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ Some(self.element.clone())
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (usize::MAX, None)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Clone> DoubleEndedIterator for Repeat<A> {
+ #[inline]
+ fn next_back(&mut self) -> Option<A> {
+ Some(self.element.clone())
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<A: Clone> FusedIterator for Repeat<A> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
--- /dev/null
+use crate::iter::{FusedIterator, TrustedLen};
+
+/// Creates a new iterator that repeats elements of type `A` endlessly by
+/// applying the provided closure, the repeater, `F: FnMut() -> A`.
+///
+/// The `repeat_with()` function calls the repeater over and over again.
+///
+/// Infinite iterators like `repeat_with()` are often used with adapters like
+/// [`Iterator::take()`], in order to make them finite.
+///
+/// If the element type of the iterator you need implements [`Clone`], and
+/// it is OK to keep the source element in memory, you should instead use
+/// the [`repeat()`] function.
+///
+/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`].
+/// If you need `repeat_with()` to return a [`DoubleEndedIterator`],
+/// please open a GitHub issue explaining your use case.
+///
+/// [`repeat()`]: crate::iter::repeat
+/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // let's assume we have some value of a type that is not `Clone`
+/// // or which don't want to have in memory just yet because it is expensive:
+/// #[derive(PartialEq, Debug)]
+/// struct Expensive;
+///
+/// // a particular value forever:
+/// let mut things = iter::repeat_with(|| Expensive);
+///
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// ```
+///
+/// Using mutation and going finite:
+///
+/// ```rust
+/// use std::iter;
+///
+/// // From the zeroth to the third power of two:
+/// let mut curr = 1;
+/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp })
+/// .take(4);
+///
+/// assert_eq!(Some(1), pow2.next());
+/// assert_eq!(Some(2), pow2.next());
+/// assert_eq!(Some(4), pow2.next());
+/// assert_eq!(Some(8), pow2.next());
+///
+/// // ... and now we're done
+/// assert_eq!(None, pow2.next());
+/// ```
+#[inline]
+#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
+pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
+ RepeatWith { repeater }
+}
+
+/// An iterator that repeats elements of type `A` endlessly by
+/// applying the provided closure `F: FnMut() -> A`.
+///
+/// This `struct` is created by the [`repeat_with()`] function.
+/// See its documentation for more.
+#[derive(Copy, Clone, Debug)]
+#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
+pub struct RepeatWith<F> {
+ repeater: F,
+}
+
+#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
+impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ Some((self.repeater)())
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (usize::MAX, None)
+ }
+}
+
+#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
+impl<A, F: FnMut() -> A> FusedIterator for RepeatWith<F> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {}
--- /dev/null
+use crate::{fmt, iter::FusedIterator};
+
+/// Creates a new iterator where each successive item is computed based on the preceding one.
+///
+/// The iterator starts with the given first item (if any)
+/// and calls the given `FnMut(&T) -> Option<T>` closure to compute each item’s successor.
+///
+/// ```
+/// use std::iter::successors;
+///
+/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
+/// assert_eq!(powers_of_10.collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
+/// ```
+#[stable(feature = "iter_successors", since = "1.34.0")]
+pub fn successors<T, F>(first: Option<T>, succ: F) -> Successors<T, F>
+where
+ F: FnMut(&T) -> Option<T>,
+{
+ // If this function returned `impl Iterator<Item=T>`
+ // it could be based on `unfold` and not need a dedicated type.
+ // However having a named `Successors<T, F>` type allows it to be `Clone` when `T` and `F` are.
+ Successors { next: first, succ }
+}
+
+/// An new iterator where each successive item is computed based on the preceding one.
+///
+/// This `struct` is created by the [`iter::successors()`] function.
+/// See its documentation for more.
+///
+/// [`iter::successors()`]: successors
+#[derive(Clone)]
+#[stable(feature = "iter_successors", since = "1.34.0")]
+pub struct Successors<T, F> {
+ next: Option<T>,
+ succ: F,
+}
+
+#[stable(feature = "iter_successors", since = "1.34.0")]
+impl<T, F> Iterator for Successors<T, F>
+where
+ F: FnMut(&T) -> Option<T>,
+{
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ let item = self.next.take()?;
+ self.next = (self.succ)(&item);
+ Some(item)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.next.is_some() { (1, None) } else { (0, Some(0)) }
+ }
+}
+
+#[stable(feature = "iter_successors", since = "1.34.0")]
+impl<T, F> FusedIterator for Successors<T, F> where F: FnMut(&T) -> Option<T> {}
+
+#[stable(feature = "iter_successors", since = "1.34.0")]
+impl<T: fmt::Debug, F> fmt::Debug for Successors<T, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Successors").field("next", &self.next).finish()
+ }
+}
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
-#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))]
+#![feature(rustc_allow_const_fn_unstable)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(const_overflowing_int_methods)]
#![feature(const_int_unchecked_arith)]
#![feature(const_mut_refs)]
-#![feature(const_int_pow)]
-#![feature(constctlz)]
#![feature(const_cttz)]
#![feature(const_panic)]
#![feature(const_pin)]
#![feature(const_fn)]
#![feature(const_fn_union)]
-#![cfg_attr(not(bootstrap), feature(const_impl_trait))]
+#![feature(const_impl_trait)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(const_generics)]
#![feature(nll)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
-#![feature(optin_builtin_traits)]
+#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
+#![cfg_attr(not(bootstrap), feature(auto_traits))]
#![feature(or_patterns)]
#![feature(prelude_import)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
-#![cfg_attr(not(bootstrap), feature(unsized_fn_params))]
-#![cfg_attr(bootstrap, feature(unsized_locals))]
-#![cfg_attr(bootstrap, feature(untagged_unions))]
+#![feature(unsized_fn_params)]
#![feature(unwind_attributes)]
#![feature(variant_count)]
#![feature(tbm_target_feature)]
unused_imports,
unsafe_op_in_unsafe_fn
)]
-#[cfg_attr(not(bootstrap), allow(non_autolinks))]
+#[allow(non_autolinks)]
// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
#[allow(clashing_extern_declarations)]
#[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")]
macro_rules! panic {
() => (
$crate::panic!("explicit panic")
// The reborrows below are intentional. Without them, the stack slot for the
// borrow is initialized even before the values are compared, leading to a
// noticeable slow down.
- panic!(r#"assertion failed: `(left == right)`
+ $crate::panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`"#, &*left_val, &*right_val)
}
// The reborrows below are intentional. Without them, the stack slot for the
// borrow is initialized even before the values are compared, leading to a
// noticeable slow down.
- panic!(r#"assertion failed: `(left == right)`
+ $crate::panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`: {}"#, &*left_val, &*right_val,
$crate::format_args!($($arg)+))
// The reborrows below are intentional. Without them, the stack slot for the
// borrow is initialized even before the values are compared, leading to a
// noticeable slow down.
- panic!(r#"assertion failed: `(left != right)`
+ $crate::panic!(r#"assertion failed: `(left != right)`
left: `{:?}`,
right: `{:?}`"#, &*left_val, &*right_val)
}
// The reborrows below are intentional. Without them, the stack slot for the
// borrow is initialized even before the values are compared, leading to a
// noticeable slow down.
- panic!(r#"assertion failed: `(left != right)`
+ $crate::panic!(r#"assertion failed: `(left != right)`
left: `{:?}`,
right: `{:?}`: {}"#, &*left_val, &*right_val,
$crate::format_args!($($arg)+))
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "debug_assert_macro")]
macro_rules! debug_assert {
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert!($($arg)*); })
}
///
/// # Panics
///
-/// This will always [`panic!`]
+/// This will always [`panic!`].
///
/// # Examples
///
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! unreachable {
() => ({
- panic!("internal error: entered unreachable code")
+ $crate::panic!("internal error: entered unreachable code")
});
($msg:expr $(,)?) => ({
$crate::unreachable!("{}", $msg)
});
($fmt:expr, $($arg:tt)*) => ({
- panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
+ $crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
});
}
/// This allows your code to type-check, which is useful if you are prototyping or
/// implementing a trait that requires multiple methods which you don't plan of using all of.
///
-/// The difference between `unimplemented!` and [`todo!`](macro.todo.html) is that while `todo!`
+/// The difference between `unimplemented!` and [`todo!`] is that while `todo!`
/// conveys an intent of implementing the functionality later and the message is "not yet
/// implemented", `unimplemented!` makes no such claims. Its message is "not implemented".
/// Also some IDEs will mark `todo!`s.
///
/// # Panics
///
-/// This will always [panic!](macro.panic.html) because `unimplemented!` is just a
-/// shorthand for `panic!` with a fixed, specific message.
+/// This will always [`panic!`] because `unimplemented!` is just a shorthand for `panic!` with a
+/// fixed, specific message.
///
/// Like `panic!`, this macro has a second form for displaying custom values.
///
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! unimplemented {
- () => (panic!("not implemented"));
- ($($arg:tt)+) => (panic!("not implemented: {}", $crate::format_args!($($arg)+)));
+ () => ($crate::panic!("not implemented"));
+ ($($arg:tt)+) => ($crate::panic!("not implemented: {}", $crate::format_args!($($arg)+)));
}
/// Indicates unfinished code.
///
/// # Panics
///
-/// This will always [panic!](macro.panic.html)
+/// This will always [`panic!`].
///
/// # Examples
///
#[macro_export]
#[stable(feature = "todo_macro", since = "1.40.0")]
macro_rules! todo {
- () => (panic!("not yet implemented"));
- ($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
+ () => ($crate::panic!("not yet implemented"));
+ ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
}
/// Definitions of built-in macros.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "assert_macro")]
+ #[allow_internal_unstable(core_panic)]
macro_rules! assert {
($cond:expr $(,)?) => {{ /* compiler built-in */ }};
($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
/// Required trait for constants used in pattern matches.
///
/// Any type that derives `Eq` automatically implements this trait, *regardless*
-/// of whether its type-parameters implement `Eq`.
+/// of whether its type parameters implement `Eq`.
///
-/// This is a hack to workaround a limitation in our type-system.
+/// This is a hack to work around a limitation in our type system.
///
-/// Background:
+/// # Background
///
/// We want to require that types of consts used in pattern matches
/// have the attribute `#[derive(PartialEq, Eq)]`.
///
/// In a more ideal world, we could check that requirement by just checking that
-/// the given type implements both (1.) the `StructuralPartialEq` trait *and*
-/// (2.) the `Eq` trait. However, you can have ADTs that *do* `derive(PartialEq, Eq)`,
+/// the given type implements both the `StructuralPartialEq` trait *and*
+/// the `Eq` trait. However, you can have ADTs that *do* `derive(PartialEq, Eq)`,
/// and be a case that we want the compiler to accept, and yet the constant's
/// type fails to implement `Eq`.
///
/// ```rust
/// #[derive(PartialEq, Eq)]
/// struct Wrap<X>(X);
+///
/// fn higher_order(_: &()) { }
+///
/// const CFN: Wrap<fn(&())> = Wrap(higher_order);
+///
/// fn main() {
/// match CFN {
/// CFN => {}
///
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
#[stable(feature = "pin", since = "1.33.0")]
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PhantomPinned;
#[stable(feature = "pin", since = "1.33.0")]
/// ```rust,no_run
/// use std::mem::MaybeUninit;
///
- /// enum NotZero { One = 1, Two = 2 };
+ /// enum NotZero { One = 1, Two = 2 }
///
/// let x = MaybeUninit::<(u8, NotZero)>::zeroed();
/// let x = unsafe { x.assume_init() };
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
- /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); }
+ /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); }
/// // Create a reference into the `MaybeUninit<T>`. This is okay because we initialized it.
/// let x_vec = unsafe { &*x.as_ptr() };
/// assert_eq!(x_vec.len(), 3);
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
- /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); }
+ /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); }
/// // Create a reference into the `MaybeUninit<Vec<u32>>`.
/// // This is okay because we initialized it.
/// let x_vec = unsafe { &mut *x.as_mut_ptr() };
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
- /// x.write(Some(vec![0,1,2]));
+ /// x.write(Some(vec![0, 1, 2]));
/// let x1 = unsafe { x.assume_init_read() };
/// let x2 = unsafe { x.assume_init_read() };
/// // We now created two copies of the same vector, leading to a double-free ⚠️ when
self.abs_private() < Self::INFINITY
}
+ /// Returns `true` if the number is [subnormal].
+ ///
+ /// ```
+ /// #![feature(is_subnormal)]
+ /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
+ /// let max = f32::MAX;
+ /// let lower_than_min = 1.0e-40_f32;
+ /// let zero = 0.0_f32;
+ ///
+ /// assert!(!min.is_subnormal());
+ /// assert!(!max.is_subnormal());
+ ///
+ /// assert!(!zero.is_subnormal());
+ /// assert!(!f32::NAN.is_subnormal());
+ /// assert!(!f32::INFINITY.is_subnormal());
+ /// // Values between `0` and `min` are Subnormal.
+ /// assert!(lower_than_min.is_subnormal());
+ /// ```
+ /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+ #[unstable(feature = "is_subnormal", issue = "79288")]
+ #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+ #[inline]
+ pub const fn is_subnormal(self) -> bool {
+ matches!(self.classify(), FpCategory::Subnormal)
+ }
+
/// Returns `true` if the number is neither zero, infinite,
/// [subnormal], or `NaN`.
///
self.abs_private() < Self::INFINITY
}
+ /// Returns `true` if the number is [subnormal].
+ ///
+ /// ```
+ /// #![feature(is_subnormal)]
+ /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64
+ /// let max = f64::MAX;
+ /// let lower_than_min = 1.0e-308_f64;
+ /// let zero = 0.0_f64;
+ ///
+ /// assert!(!min.is_subnormal());
+ /// assert!(!max.is_subnormal());
+ ///
+ /// assert!(!zero.is_subnormal());
+ /// assert!(!f64::NAN.is_subnormal());
+ /// assert!(!f64::INFINITY.is_subnormal());
+ /// // Values between `0` and `min` are Subnormal.
+ /// assert!(lower_than_min.is_subnormal());
+ /// ```
+ /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+ #[unstable(feature = "is_subnormal", issue = "79288")]
+ #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+ #[inline]
+ pub const fn is_subnormal(self) -> bool {
+ matches!(self.classify(), FpCategory::Subnormal)
+ }
+
/// Returns `true` if the number is neither zero, infinite,
/// [subnormal], or `NaN`.
///
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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_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
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))]
+ #[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
#[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
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))]
+ #[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
assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
$EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
```"),
#[stable(feature = "no_panic_pow", since = "1.34.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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]
// overflow cases it instead ends up returning the maximum value
// of the type, and can return 0 for 0.
#[inline]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
const fn one_less_than_next_power_of_two(self) -> Self {
if self <= 1 { return 0; }
assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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 {
```"),
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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)
}
```"),
#[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
reason = "needs decision on wrapping behaviour")]
- #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")]
+ #[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)
}
#[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
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))]
+ #[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
#[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
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))]
+ #[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
/// each can be indexed mutably and immutably.
///
/// ```
-/// use std::ops::{Index,IndexMut};
+/// use std::ops::{Index, IndexMut};
///
/// #[derive(Debug)]
/// enum Side {
#[inline]
#[track_caller]
-#[cfg_attr(not(bootstrap), lang = "panic_str")] // needed for const-evaluated panics
+#[lang = "panic_str"] // needed for const-evaluated panics
pub fn panic_str(expr: &str) -> ! {
panic_fmt(format_args!("{}", expr));
}
//! provided at this point are very minimal:
//!
//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst].
-//! * All pointers (except for the null pointer) are valid for all operations of
-//! [size zero][zst].
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
//! be *dereferenceable*: the memory range of the given size starting at the pointer must all be
//! within the bounds of a single allocated object. Note that in Rust,
//! every (stack-allocated) variable is considered a separate allocated object.
+//! * Even for operations of [size zero][zst], the pointer must not be pointing to deallocated
+//! memory, i.e., deallocation makes pointers invalid even for zero-sized operations. However,
+//! casting any non-zero integer *literal* to a pointer is valid for zero-sized accesses, even if
+//! some memory happens to exist at that address and gets deallocated. This corresponds to writing
+//! your own allocator: allocating zero-sized objects is not very hard. The canonical way to
+//! obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`].
//! * All accesses performed by functions in this module are *non-atomic* in the sense
//! of [atomic operations] used to synchronize between threads. This means it is
//! undefined behavior to perform two concurrent accesses to the same location from different
// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
-// ignore-tidy-undocumented-unsafe
-
use crate::cmp;
use crate::mem;
// search the body of the text
let repeated_x = repeat_byte(x);
while offset <= len - 2 * USIZE_BYTES {
+ // SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes
+ // between the offset and the end of the slice.
unsafe {
let u = *(ptr.add(offset) as *const usize);
let v = *(ptr.add(offset + USIZE_BYTES) as *const usize);
let (min_aligned_offset, max_aligned_offset) = {
// We call this just to obtain the length of the prefix and suffix.
// In the middle we always process two chunks at once.
+ // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size differences
+ // which are handled by `align_to`.
let (prefix, _, suffix) = unsafe { text.align_to::<(Chunk, Chunk)>() };
(prefix.len(), len - suffix.len())
};
let chunk_bytes = mem::size_of::<Chunk>();
while offset > min_aligned_offset {
+ // SAFETY: offset starts at len - suffix.len(), as long as it is greater than
+ // min_aligned_offset (prefix.len()) the remaining distance is at least 2 * chunk_bytes.
unsafe {
let u = *(ptr.offset(offset as isize - 2 * chunk_bytes as isize) as *const Chunk);
let v = *(ptr.offset(offset as isize - chunk_bytes as isize) as *const Chunk);
#[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")]
#[inline]
// SAFETY: const sound because we transmute out the length field as a usize (which it must be)
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_union))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_union))]
+ #[rustc_allow_const_fn_unstable(const_fn_union)]
pub const fn len(&self) -> usize {
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
// Only `std` can make this guarantee.
// many bytes away from the end of `self`.
// - Any initialized memory is valid `usize`.
unsafe {
- let pa: *mut T = self.get_unchecked_mut(i);
- let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
+ let ptr = self.as_mut_ptr();
+ let pa = ptr.add(i);
+ let pb = ptr.add(ln - i - chunk);
let va = ptr::read_unaligned(pa as *mut usize);
let vb = ptr::read_unaligned(pb as *mut usize);
ptr::write_unaligned(pa as *mut usize, vb.swap_bytes());
// always respected, ensuring the `pb` pointer can be used
// safely.
unsafe {
- let pa: *mut T = self.get_unchecked_mut(i);
- let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
+ let ptr = self.as_mut_ptr();
+ let pa = ptr.add(i);
+ let pb = ptr.add(ln - i - chunk);
let va = ptr::read_unaligned(pa as *mut u32);
let vb = ptr::read_unaligned(pb as *mut u32);
ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16));
// aligned, and can be read from and written to.
unsafe {
// Unsafe swap to avoid the bounds check in safe swap.
- let pa: *mut T = self.get_unchecked_mut(i);
- let pb: *mut T = self.get_unchecked_mut(ln - i - 1);
+ let ptr = self.as_mut_ptr();
+ let pa = ptr.add(i);
+ let pb = ptr.add(ln - i - 1);
ptr::swap(pa, pb);
}
i += 1;
/// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
/// (1, 21), (2, 34), (4, 55)];
///
- /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9));
- /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7));
- /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13));
- /// let r = s.binary_search_by_key(&1, |&(a,b)| b);
+ /// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9));
+ /// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7));
+ /// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13));
+ /// let r = s.binary_search_by_key(&1, |&(a, b)| b);
/// assert!(match r { Ok(1..=4) => true, _ => false, });
/// ```
#[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
/// buf.fill(1);
/// assert_eq!(buf, vec![1; 10]);
/// ```
+ #[doc(alias = "memset")]
#[unstable(feature = "slice_fill", issue = "70758")]
pub fn fill(&mut self, value: T)
where
}
}
+ /// Fills `self` with elements returned by calling a closure repeatedly.
+ ///
+ /// This method uses a closure to create new values. If you'd rather
+ /// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`]
+ /// trait to generate values, you can pass [`Default::default`] as the
+ /// argument.
+ ///
+ /// [`fill`]: #method.fill
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_fill_with)]
+ ///
+ /// let mut buf = vec![1; 10];
+ /// buf.fill_with(Default::default);
+ /// assert_eq!(buf, vec![0; 10]);
+ /// ```
+ #[unstable(feature = "slice_fill_with", issue = "79221")]
+ pub fn fill_with<F>(&mut self, mut f: F)
+ where
+ F: FnMut() -> T,
+ {
+ for el in self {
+ *el = f();
+ }
+ }
+
/// Copies the elements from `src` into `self`.
///
/// The length of `src` must be the same as `self`.
///
/// [`clone_from_slice`]: #method.clone_from_slice
/// [`split_at_mut`]: #method.split_at_mut
+ #[doc(alias = "memcpy")]
#[stable(feature = "copy_from_slice", since = "1.9.0")]
pub fn copy_from_slice(&mut self, src: &[T])
where
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")]
-#[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))]
-#[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))]
+#[rustc_allow_const_fn_unstable(const_fn_transmute)]
pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
// SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8.
// Also relies on `&str` and `&[u8]` having the same layout.
#[rustc_const_stable(feature = "str_as_bytes", since = "1.32.0")]
#[inline(always)]
#[allow(unused_attributes)]
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))]
+ #[rustc_allow_const_fn_unstable(const_fn_transmute)]
pub const fn as_bytes(&self) -> &[u8] {
// SAFETY: const sound because we transmute two types with the same layout
unsafe { mem::transmute(self) }
let old_offset = index;
macro_rules! err {
($error_len: expr) => {
- return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len });
+ return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len })
};
}
//!
//! * PowerPC and MIPS platforms with 32-bit pointers do not have `AtomicU64` or
//! `AtomicI64` types.
-//! * ARM platforms like `armv5te` that aren't for Linux do not have any atomics
-//! at all.
-//! * ARM targets with `thumbv6m` do not have atomic operations at all.
+//! * ARM platforms like `armv5te` that aren't for Linux only provide `load`
+//! and `store` operations, and do not support Compare and Swap (CAS)
+//! operations, such as `swap`, `fetch_add`, etc. Additionally on Linux,
+//! these CAS operations are implemented via [operating system support], which
+//! may come with a performance penalty.
+//! * ARM targets with `thumbv6m` only provide `load` and `store` operations,
+//! and do not support Compare and Swap (CAS) operations, such as `swap`,
+//! `fetch_add`, etc.
+//!
+//! [operating system support]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt
//!
//! Note that future platforms may be added that also do not have support for
//! some atomic operations. Maximally portable code will want to be careful
#[rustc_promotable]
#[stable(feature = "futures_api", since = "1.36.0")]
#[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_fn_ptr_basics))]
+ #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
pub const fn new(
clone: unsafe fn(*const ()) -> RawWaker,
wake: unsafe fn(*const ()),
assert_eq!(it.next_if_eq(""), None);
}
+#[test]
+fn test_iterator_peekable_mut() {
+ let mut it = vec![1, 2, 3].into_iter().peekable();
+ if let Some(p) = it.peek_mut() {
+ if *p == 1 {
+ *p = 5;
+ }
+ }
+ assert_eq!(it.collect::<Vec<_>>(), vec![5, 2, 3]);
+}
+
/// This is an iterator that follows the Iterator contract,
/// but it is not fused. After having returned None once, it will start
/// producing elements if .next() is called again.
#![feature(unwrap_infallible)]
#![feature(option_unwrap_none)]
#![feature(peekable_next_if)]
+#![feature(peekable_peek_mut)]
#![feature(partition_point)]
#![feature(once_cell)]
#![feature(unsafe_block_in_unsafe_fn)]
let five = "Five".to_string();
match Some(five) {
Some(s) => assert_eq!(s, "Five"),
- None => panic!("unexpected None while matching on Some(String { ... })"),
+ None => panic!("{}", "unexpected None while matching on Some(String { ... })"),
}
}
--- /dev/null
+int_module!(i128, i128);
assert_eq!(B.rotate_left(0), B);
assert_eq!(C.rotate_left(0), C);
// Rotating by a multiple of word size should also have no effect
- assert_eq!(A.rotate_left(64), A);
- assert_eq!(B.rotate_left(64), B);
- assert_eq!(C.rotate_left(64), C);
+ assert_eq!(A.rotate_left(128), A);
+ assert_eq!(B.rotate_left(128), B);
+ assert_eq!(C.rotate_left(128), C);
}
#[test]
#[macro_use]
mod int_macros;
+mod i128;
mod i16;
mod i32;
mod i64;
#[macro_use]
mod uint_macros;
+mod u128;
mod u16;
mod u32;
mod u64;
--- /dev/null
+uint_module!(u128, u128);
assert_eq!(B.rotate_left(0), B);
assert_eq!(C.rotate_left(0), C);
// Rotating by a multiple of word size should also have no effect
- assert_eq!(A.rotate_left(64), A);
- assert_eq!(B.rotate_left(64), B);
- assert_eq!(C.rotate_left(64), C);
+ assert_eq!(A.rotate_left(128), A);
+ assert_eq!(B.rotate_left(128), B);
+ assert_eq!(C.rotate_left(128), C);
}
#[test]
struct Pair {
fst: isize,
snd: isize,
- };
+ }
let mut p = Pair { fst: 10, snd: 20 };
let pptr: *mut Pair = &mut p;
let iptr: *mut isize = pptr as *mut isize;
abort();
cfg_if::cfg_if! {
- if #[cfg(any(unix, target_os = "cloudabi"))] {
+ if #[cfg(unix)] {
unsafe fn abort() -> ! {
libc::abort();
}
mod real_imp;
} else if #[cfg(any(
all(target_family = "windows", target_env = "gnu"),
- target_os = "cloudabi",
target_os = "psp",
target_family = "unix",
all(target_vendor = "fortanix", target_env = "sgx"),
}
impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))]
+ #[rustc_allow_const_fn_unstable(const_fn)]
pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
extern "C" fn run(
bridge: Bridge<'_>,
}
impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))]
+ #[rustc_allow_const_fn_unstable(const_fn)]
pub const fn expand2(
f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
) -> Self {
}
}
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))]
+ #[rustc_allow_const_fn_unstable(const_fn)]
pub const fn custom_derive(
trait_name: &'static str,
attributes: &'static [&'static str],
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
}
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))]
+ #[rustc_allow_const_fn_unstable(const_fn)]
pub const fn attr(
name: &'static str,
expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
ProcMacro::Attr { name, client: Client::expand2(expand) }
}
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))]
+ #[rustc_allow_const_fn_unstable(const_fn)]
pub const fn bang(
name: &'static str,
expand: fn(crate::TokenStream) -> crate::TokenStream,
pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
impl<T: LambdaL> ScopedCell<T> {
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))]
+ #[rustc_allow_const_fn_unstable(const_fn)]
pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self {
ScopedCell(Cell::new(value))
}
test(no_crate_inject, attr(deny(warnings))),
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
-#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))]
+#![feature(rustc_allow_const_fn_unstable)]
#![feature(nll)]
#![feature(staged_api)]
#![feature(const_fn)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(negative_impls)]
-#![feature(optin_builtin_traits)]
+#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
+#![cfg_attr(not(bootstrap), feature(auto_traits))]
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
}
}
+#[stable(feature = "proc_macro_punct_eq", since = "1.49.0")]
+impl PartialEq<char> for Punct {
+ fn eq(&self, rhs: &char) -> bool {
+ self.as_char() == *rhs
+ }
+}
+
/// An identifier (`ident`).
#[derive(Clone)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
#![feature(proc_macro_span)]
-use proc_macro::LineColumn;
+use proc_macro::{LineColumn, Punct};
#[test]
fn test_line_column_ord() {
assert!(line0_column0 < line0_column1);
assert!(line0_column1 < line1_column0);
}
+
+#[test]
+fn test_punct_eq() {
+ // Good enough if it typechecks, since proc_macro::Punct can't exist in a test.
+ fn _check(punct: Punct) {
+ let _ = punct == ':';
+ }
+}
// headers or footers.
//
// Note that the actual module entry point is located in the C runtime startup
-// object (usually called `crtX.o), which then invokes initialization callbacks
+// object (usually called `crtX.o`), which then invokes initialization callbacks
// of other runtime components (registered via yet another special image section).
-#![feature(no_core, lang_items, optin_builtin_traits)]
+#![feature(no_core)]
+#![feature(lang_items)]
+#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
+#![cfg_attr(not(bootstrap), feature(auto_traits))]
#![crate_type = "rlib"]
#![no_core]
#![allow(non_camel_case_types)]
// See rsbegin.rs for details.
-#![feature(no_core, lang_items, optin_builtin_traits)]
+#![feature(no_core)]
+#![feature(lang_items)]
+#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
+#![cfg_attr(not(bootstrap), feature(auto_traits))]
#![crate_type = "rlib"]
#![no_core]
hashbrown = { version = "0.9.0", default-features = false, features = ['rustc-dep-of-std'] }
# Dependencies of the `backtrace` crate
-addr2line = { version = "0.13.0", optional = true, default-features = false }
+addr2line = { version = "0.14.0", optional = true, default-features = false }
rustc-demangle = { version = "0.1.18", features = ['rustc-dep-of-std'] }
miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
[dependencies.object]
-version = "0.20"
+version = "0.22"
optional = true
default-features = false
-features = ['read_core', 'elf', 'macho', 'pe']
+features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
[dev-dependencies]
rand = "0.7"
|| target.contains("uwp")
|| target.contains("windows")
|| target.contains("fuchsia")
- || target.contains("cloudabi")
|| (target.contains("sgx") && target.contains("fortanix"))
|| target.contains("hermit")
|| target.contains("l4re")
/// # Examples
///
/// ```
- /// #![feature(clamp)]
/// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0);
/// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0);
/// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0);
/// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan());
/// ```
#[must_use = "method returns a new number and does not mutate the original value"]
- #[unstable(feature = "clamp", issue = "44095")]
+ #[stable(feature = "clamp", since = "1.50.0")]
#[inline]
pub fn clamp(self, min: f32, max: f32) -> f32 {
assert!(min <= max);
/// # Examples
///
/// ```
- /// #![feature(clamp)]
/// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0);
/// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0);
/// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0);
/// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan());
/// ```
#[must_use = "method returns a new number and does not mutate the original value"]
- #[unstable(feature = "clamp", issue = "44095")]
+ #[stable(feature = "clamp", since = "1.50.0")]
#[inline]
pub fn clamp(self, min: f64, max: f64) -> f64 {
assert!(min <= max);
/// behavior when `ptr` is used inside the `unsafe` block:
///
/// ```no_run
- /// # #![allow(unused_must_use)] #![cfg_attr(not(bootstrap), allow(temporary_cstring_as_ptr))]
+ /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
/// use std::ffi::CString;
///
/// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
#![stable(feature = "rust1", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
-#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
mod tests;
use crate::ffi::OsString;
/// Creates a new hard link on the filesystem.
///
-/// The `dst` path will be a link pointing to the `src` path. Note that systems
-/// often require these two paths to both be located on the same filesystem.
+/// The `link` path will be a link pointing to the `original` path. Note that
+/// systems often require these two paths to both be located on the same
+/// filesystem.
///
-/// If `src` names a symbolic link, it is platform-specific whether the symbolic
-/// link is followed. On platforms where it's possible to not follow it, it is
-/// not followed, and the created hard link points to the symbolic link itself.
+/// If `original` names a symbolic link, it is platform-specific whether the
+/// symbolic link is followed. On platforms where it's possible to not follow
+/// it, it is not followed, and the created hard link points to the symbolic
+/// link itself.
///
/// # Platform-specific behavior
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
-/// * The `src` path is not a file or doesn't exist.
+/// * The `original` path is not a file or doesn't exist.
///
/// # Examples
///
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- fs_imp::link(src.as_ref(), dst.as_ref())
+pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ fs_imp::link(original.as_ref(), link.as_ref())
}
/// Creates a new symbolic link on the filesystem.
///
-/// The `dst` path will be a symbolic link pointing to the `src` path.
+/// The `link` path will be a symbolic link pointing to the `original` path.
/// On Windows, this will be a file symlink, not a directory symlink;
/// for this reason, the platform-specific [`std::os::unix::fs::symlink`]
/// and [`std::os::windows::fs::symlink_file`] or [`symlink_dir`] should be
reason = "replaced with std::os::unix::fs::symlink and \
std::os::windows::fs::{symlink_file, symlink_dir}"
)]
-pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- fs_imp::symlink(src.as_ref(), dst.as_ref())
+pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ fs_imp::symlink(original.as_ref(), link.as_ref())
}
/// Reads a symbolic link, returning the file that the link points to.
///
/// # Differences between the 2015 and 2018 editions
///
-/// In the 2015 edition parameters pattern where not needed for traits:
+/// In the 2015 edition the parameters pattern was not needed for traits:
///
/// ```rust,edition2015
/// trait Tr {
#![needs_panic_runtime]
// std may use features in a platform-specific way
#![allow(unused_features)]
-#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))]
+#![feature(rustc_allow_const_fn_unstable)]
#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
#![cfg_attr(
all(target_vendor = "fortanix", target_env = "sgx"),
#![feature(asm)]
#![feature(associated_type_bounds)]
#![feature(atomic_mut_ptr)]
-#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(c_variadic)]
#![feature(cfg_accessible)]
#![feature(cfg_target_thread_local)]
#![feature(char_error_internals)]
#![feature(char_internals)]
-#![feature(clamp)]
#![feature(concat_idents)]
#![feature(const_cstr_unchecked)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(once_cell)]
-#![feature(optin_builtin_traits)]
+#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
+#![cfg_attr(not(bootstrap), feature(auto_traits))]
#![feature(or_patterns)]
#![feature(panic_info_message)]
#![feature(panic_internals)]
#![feature(raw)]
#![feature(raw_ref_macros)]
#![feature(ready_macro)]
-#![feature(refcell_take)]
#![feature(rustc_attrs)]
#![feature(rustc_private)]
#![feature(shrink_to)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsafe_cell_get_mut)]
#![feature(unsafe_cell_raw_get)]
-#![cfg_attr(bootstrap, feature(untagged_unions))]
#![feature(unwind_attributes)]
#![feature(vec_into_raw_parts)]
#![feature(wake_trait)]
#[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")]
macro_rules! panic {
() => ({ $crate::panic!("explicit panic") });
($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) });
/// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false);
/// ```
+ #[rustc_const_stable(feature = "const_ip", since = "1.50.0")]
#[stable(feature = "ipaddr_checker", since = "1.16.0")]
- pub fn is_ipv4(&self) -> bool {
+ pub const fn is_ipv4(&self) -> bool {
matches!(self, IpAddr::V4(_))
}
/// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true);
/// ```
+ #[rustc_const_stable(feature = "const_ip", since = "1.50.0")]
#[stable(feature = "ipaddr_checker", since = "1.16.0")]
- pub fn is_ipv6(&self) -> bool {
+ pub const fn is_ipv6(&self) -> bool {
matches!(self, IpAddr::V6(_))
}
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
- #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))]
- #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))]
+ #[rustc_allow_const_fn_unstable(const_fn_transmute)]
pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
let addr16 = [
a.to_be(),
#![deny(unsafe_op_in_unsafe_fn)]
-#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))]
+#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
use crate::io::prelude::*;
-#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
mod tests;
use crate::fmt;
macro_rules! test_is_power_of_two {
($test_name:ident, $T:ident) => {
+ #[test]
fn $test_name() {
- #![test]
assert_eq!((0 as $T).is_power_of_two(), false);
assert_eq!((1 as $T).is_power_of_two(), true);
assert_eq!((2 as $T).is_power_of_two(), true);
macro_rules! test_next_power_of_two {
($test_name:ident, $T:ident) => {
+ #[test]
fn $test_name() {
- #![test]
assert_eq!((0 as $T).next_power_of_two(), 1);
let mut next_power = 1;
for i in 1 as $T..40 {
macro_rules! test_checked_next_power_of_two {
($test_name:ident, $T:ident) => {
+ #[test]
fn $test_name() {
- #![test]
assert_eq!((0 as $T).checked_next_power_of_two(), Some(1));
let smax = $T::MAX >> 1;
assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1));
#![stable(feature = "process", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
-#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
mod tests;
use crate::io::prelude::*;
///
/// [panic hook]: crate::panic::set_hook
#[stable(feature = "process_abort", since = "1.17.0")]
+#[cold]
pub fn abort() -> ! {
crate::sys::abort_internal();
}
+++ /dev/null
-// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-// 1. Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-// SUCH DAMAGE.
-
-#[cfg(feature = "bitflags")]
-use bitflags::bitflags;
-
-// Minimal implementation of bitflags! in case we can't depend on the bitflags
-// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't
-// actually truncate.
-#[cfg(not(feature = "bitflags"))]
-macro_rules! bitflags {
- (
- $(#[$attr:meta])*
- pub struct $name:ident: $type:ty {
- $($(#[$const_attr:meta])* const $const:ident = $val:expr;)*
- }
- ) => {
- $(#[$attr])*
- #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
- pub struct $name { bits: $type }
- impl $name {
- $($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)*
- pub fn bits(&self) -> $type { self.bits }
- pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } }
- }
- }
-}
+++ /dev/null
-// Copyright (c) 2016-2017 Nuxi <https://nuxi.nl/> and contributors.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-// 1. Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-// SUCH DAMAGE.
-//
-// This file is automatically generated. Do not edit.
-//
-// Source: https://github.com/NuxiNL/cloudabi
-
-// Appease Rust's tidy.
-// ignore-tidy-linelength
-
-//! **PLEASE NOTE: This entire crate including this
-//! documentation is automatically generated from
-//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt)**
-//!
-//! # Nuxi CloudABI
-//!
-//! CloudABI is what you get if you take POSIX, add capability-based
-//! security, and remove everything that's incompatible with that. The
-//! result is a minimal ABI consisting of only 49 syscalls.
-//!
-//! CloudABI doesn't have its own kernel, but instead is implemented in existing
-//! kernels: FreeBSD has CloudABI support for x86-64 and arm64, and [a patch-set
-//! for NetBSD](https://github.com/NuxiNL/netbsd) and [a patch-set for
-//! Linux](https://github.com/NuxiNL/linux) are available as well. This means that
-//! CloudABI binaries can be executed on different operating systems, without any
-//! modification.
-//!
-//! ## Capability-Based Security
-//!
-//! Capability-based security means that processes can only perform
-//! actions that have no global impact. Processes cannot open files by
-//! their absolute path, cannot open network connections, and cannot
-//! observe global system state such as the process table.
-//!
-//! The capabilities of a process are fully determined by its set of open
-//! file descriptors (fds). For example, files can only be opened if the
-//! process already has a file descriptor to a directory the file is in.
-//!
-//! Unlike in POSIX, where processes are normally started with file
-//! descriptors 0, 1, and 2 reserved for standard input, output, and
-//! error, CloudABI does not reserve any file descriptor numbers for
-//! specific purposes.
-//!
-//! In CloudABI, a process depends on its parent process to launch it with
-//! the right set of resources, since the process will not be able to open
-//! any new resources. For example, a simple static web server would need
-//! to be started with a file descriptor to a [TCP
-//! listener](https://github.com/NuxiNL/flower), and a file descriptor to
-//! the directory for which to serve files. The web server will then be
-//! unable to do anything other than reading files in that directory, and
-//! process incoming network connections.
-//!
-//! So, unknown CloudABI binaries can safely be executed without the need
-//! for containers, virtual machines, or other sandboxing technologies.
-//!
-//! Watch [Ed Schouten's Talk at
-//! 32C3](https://www.youtube.com/watch?v=3N29vrPoDv8) for more
-//! information about what capability-based security for UNIX means.
-//!
-//! ## Cloudlibc
-//!
-//! [Cloudlibc](https://github.com/NuxiNL/cloudlibc) is an implementation
-//! of the C standard library, without all CloudABI-incompatible
-//! functions. For example, Cloudlibc does not have `printf`, but does
-//! have `fprintf`. It does not have `open`, but does have `openat`.
-//!
-//! ## CloudABI-Ports
-//!
-//! [CloudABI-Ports](https://github.com/NuxiNL/cloudabi-ports) is a
-//! collection of ports of commonly used libraries and applications to
-//! CloudABI. It contains software such as `zlib`, `libpng`, `boost`,
-//! `memcached`, and much more. The software is patched to not depend on
-//! any global state, such as files in `/etc` or `/dev`, using `open()`,
-//! etc.
-//!
-//! ## Using CloudABI
-//!
-//! Instructions for using CloudABI (including kernel modules/patches,
-//! toolchain, and ports) are available for several operating systems:
-//!
-//! - [Arch Linux](https://nuxi.nl/cloudabi/archlinux/)
-//! - [Debian, Ubuntu, and other Debian derivatives](https://nuxi.nl/cloudabi/debian/)
-//! - [FreeBSD, PC-BSD and DragonFly BSD](https://nuxi.nl/cloudabi/freebsd/)
-//! - [Mac OS X](https://nuxi.nl/cloudabi/mac/)
-//! - [NetBSD](https://nuxi.nl/cloudabi/netbsd/)
-//!
-//! ## Specification of the ABI
-//!
-//! The entire ABI is specified in a file called
-//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt),
-//! from which all
-//! [headers](https://github.com/NuxiNL/cloudabi/tree/master/headers)
-//! and documentation (including the one you're reading now) is generated.
-
-#![no_std]
-#![allow(non_camel_case_types)]
-#![allow(deprecated)] // FIXME: using `mem::uninitialized()`
-
-include!("bitflags.rs");
-
-/// File or memory access pattern advisory information.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum advice {
- /// The application expects that it will not access the
- /// specified data in the near future.
- DONTNEED = 1,
- /// The application expects to access the specified data
- /// once and then not reuse it thereafter.
- NOREUSE = 2,
- /// The application has no advice to give on its behavior
- /// with respect to the specified data.
- NORMAL = 3,
- /// The application expects to access the specified data
- /// in a random order.
- RANDOM = 4,
- /// The application expects to access the specified data
- /// sequentially from lower offsets to higher offsets.
- SEQUENTIAL = 5,
- /// The application expects to access the specified data
- /// in the near future.
- WILLNEED = 6,
-}
-
-/// Enumeration describing the kind of value stored in [`auxv`].
-#[repr(u32)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum auxtype {
- /// Base address of the binary argument data provided to
- /// [`proc_exec()`](fn.proc_exec.html).
- ARGDATA = 256,
- /// Length of the binary argument data provided to
- /// [`proc_exec()`](fn.proc_exec.html).
- ARGDATALEN = 257,
- /// Base address at which the executable is placed in
- /// memory.
- BASE = 7,
- /// Base address of a buffer of random data that may be
- /// used for non-cryptographic purposes, for example as a
- /// canary for stack smashing protection.
- CANARY = 258,
- /// Length of a buffer of random data that may be used
- /// for non-cryptographic purposes, for example as a
- /// canary for stack smashing protection.
- CANARYLEN = 259,
- /// Number of CPUs that the system this process is running
- /// on has.
- NCPUS = 260,
- /// Terminator of the auxiliary vector.
- NULL = 0,
- /// Smallest memory object size for which individual
- /// memory protection controls can be configured.
- PAGESZ = 6,
- /// Address of the first ELF program header of the
- /// executable.
- PHDR = 3,
- /// Number of ELF program headers of the executable.
- PHNUM = 4,
- /// Identifier of the process.
- ///
- /// This environment does not provide any simple numerical
- /// process identifiers, for the reason that these are not
- /// useful in distributed contexts. Instead, processes are
- /// identified by a UUID.
- ///
- /// This record should point to sixteen bytes of binary
- /// data, containing a version 4 UUID (fully random).
- PID = 263,
- /// Address of the ELF header of the vDSO.
- ///
- /// The vDSO is a shared library that is mapped in the
- /// address space of the process. It provides entry points
- /// for every system call supported by the environment,
- /// all having a corresponding symbol that is prefixed
- /// with `cloudabi_sys_`. System calls should be invoked
- /// through these entry points.
- ///
- /// The first advantage of letting processes call into a
- /// vDSO to perform system calls instead of raising
- /// hardware traps is that it allows for easy emulation of
- /// executables on top of existing operating systems. The
- /// second advantage is that in cases where an operating
- /// system provides native support for CloudABI executables,
- /// it may still implement partial userspace
- /// implementations of these system calls to improve
- /// performance (e.g., [`clock_time_get()`](fn.clock_time_get.html)). It also provides
- /// a more dynamic way of adding, removing or replacing
- /// system calls.
- SYSINFO_EHDR = 262,
- /// Thread ID of the initial thread of the process.
- TID = 261,
-}
-
-/// Identifiers for clocks.
-#[repr(u32)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum clockid {
- /// The system-wide monotonic clock, which is defined as a
- /// clock measuring real time, whose value cannot be
- /// adjusted and which cannot have negative clock jumps.
- ///
- /// The epoch of this clock is undefined. The absolute
- /// time value of this clock therefore has no meaning.
- MONOTONIC = 1,
- /// The CPU-time clock associated with the current
- /// process.
- PROCESS_CPUTIME_ID = 2,
- /// The system-wide clock measuring real time. Time value
- /// zero corresponds with 1970-01-01T00:00:00Z.
- REALTIME = 3,
- /// The CPU-time clock associated with the current thread.
- THREAD_CPUTIME_ID = 4,
-}
-
-/// A userspace condition variable.
-#[repr(C)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct condvar(pub u32);
-/// The condition variable is in its initial state. There
-/// are no threads waiting to be woken up. If the
-/// condition variable has any other value, the kernel
-/// must be called to wake up any sleeping threads.
-pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0);
-
-/// Identifier for a device containing a file system. Can be used
-/// in combination with [`inode`] to uniquely identify a file on the
-/// local system.
-#[repr(C)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct device(pub u64);
-
-/// A reference to the offset of a directory entry.
-#[repr(C)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct dircookie(pub u64);
-/// Permanent reference to the first directory entry
-/// within a directory.
-pub const DIRCOOKIE_START: dircookie = dircookie(0);
-
-/// Error codes returned by system calls.
-///
-/// Not all of these error codes are returned by the system calls
-/// provided by this environment, but are either used in userspace
-/// exclusively or merely provided for alignment with POSIX.
-#[repr(u16)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum errno {
- /// No error occurred. System call completed successfully.
- SUCCESS = 0,
- /// Argument list too long.
- TOOBIG = 1,
- /// Permission denied.
- ACCES = 2,
- /// Address in use.
- ADDRINUSE = 3,
- /// Address not available.
- ADDRNOTAVAIL = 4,
- /// Address family not supported.
- AFNOSUPPORT = 5,
- /// Resource unavailable, or operation would block.
- AGAIN = 6,
- /// Connection already in progress.
- ALREADY = 7,
- /// Bad file descriptor.
- BADF = 8,
- /// Bad message.
- BADMSG = 9,
- /// Device or resource busy.
- BUSY = 10,
- /// Operation canceled.
- CANCELED = 11,
- /// No child processes.
- CHILD = 12,
- /// Connection aborted.
- CONNABORTED = 13,
- /// Connection refused.
- CONNREFUSED = 14,
- /// Connection reset.
- CONNRESET = 15,
- /// Resource deadlock would occur.
- DEADLK = 16,
- /// Destination address required.
- DESTADDRREQ = 17,
- /// Mathematics argument out of domain of function.
- DOM = 18,
- /// Reserved.
- DQUOT = 19,
- /// File exists.
- EXIST = 20,
- /// Bad address.
- FAULT = 21,
- /// File too large.
- FBIG = 22,
- /// Host is unreachable.
- HOSTUNREACH = 23,
- /// Identifier removed.
- IDRM = 24,
- /// Illegal byte sequence.
- ILSEQ = 25,
- /// Operation in progress.
- INPROGRESS = 26,
- /// Interrupted function.
- INTR = 27,
- /// Invalid argument.
- INVAL = 28,
- /// I/O error.
- IO = 29,
- /// Socket is connected.
- ISCONN = 30,
- /// Is a directory.
- ISDIR = 31,
- /// Too many levels of symbolic links.
- LOOP = 32,
- /// File descriptor value too large.
- MFILE = 33,
- /// Too many links.
- MLINK = 34,
- /// Message too large.
- MSGSIZE = 35,
- /// Reserved.
- MULTIHOP = 36,
- /// Filename too long.
- NAMETOOLONG = 37,
- /// Network is down.
- NETDOWN = 38,
- /// Connection aborted by network.
- NETRESET = 39,
- /// Network unreachable.
- NETUNREACH = 40,
- /// Too many files open in system.
- NFILE = 41,
- /// No buffer space available.
- NOBUFS = 42,
- /// No such device.
- NODEV = 43,
- /// No such file or directory.
- NOENT = 44,
- /// Executable file format error.
- NOEXEC = 45,
- /// No locks available.
- NOLCK = 46,
- /// Reserved.
- NOLINK = 47,
- /// Not enough space.
- NOMEM = 48,
- /// No message of the desired type.
- NOMSG = 49,
- /// Protocol not available.
- NOPROTOOPT = 50,
- /// No space left on device.
- NOSPC = 51,
- /// Function not supported.
- NOSYS = 52,
- /// The socket is not connected.
- NOTCONN = 53,
- /// Not a directory or a symbolic link to a directory.
- NOTDIR = 54,
- /// Directory not empty.
- NOTEMPTY = 55,
- /// State not recoverable.
- NOTRECOVERABLE = 56,
- /// Not a socket.
- NOTSOCK = 57,
- /// Not supported, or operation not supported on socket.
- NOTSUP = 58,
- /// Inappropriate I/O control operation.
- NOTTY = 59,
- /// No such device or address.
- NXIO = 60,
- /// Value too large to be stored in data type.
- OVERFLOW = 61,
- /// Previous owner died.
- OWNERDEAD = 62,
- /// Operation not permitted.
- PERM = 63,
- /// Broken pipe.
- PIPE = 64,
- /// Protocol error.
- PROTO = 65,
- /// Protocol not supported.
- PROTONOSUPPORT = 66,
- /// Protocol wrong type for socket.
- PROTOTYPE = 67,
- /// Result too large.
- RANGE = 68,
- /// Read-only file system.
- ROFS = 69,
- /// Invalid seek.
- SPIPE = 70,
- /// No such process.
- SRCH = 71,
- /// Reserved.
- STALE = 72,
- /// Connection timed out.
- TIMEDOUT = 73,
- /// Text file busy.
- TXTBSY = 74,
- /// Cross-device link.
- XDEV = 75,
- /// Extension: Capabilities insufficient.
- NOTCAPABLE = 76,
-}
-
-bitflags! {
- /// The state of the file descriptor subscribed to with
- /// [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
- #[repr(C)]
- pub struct eventrwflags: u16 {
- /// The peer of this socket has closed or disconnected.
- const HANGUP = 0x0001;
- }
-}
-
-/// Type of a subscription to an event or its occurrence.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum eventtype {
- /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id)
- /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout).
- CLOCK = 1,
- /// Condition variable [`subscription.union.condvar.condvar`](struct.subscription_condvar.html#structfield.condvar) has
- /// been woken up and [`subscription.union.condvar.lock`](struct.subscription_condvar.html#structfield.lock) has been
- /// acquired for writing.
- CONDVAR = 2,
- /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has
- /// data available for reading. This event always triggers
- /// for regular files.
- FD_READ = 3,
- /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has
- /// capacity available for writing. This event always
- /// triggers for regular files.
- FD_WRITE = 4,
- /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for
- /// reading.
- LOCK_RDLOCK = 5,
- /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for
- /// writing.
- LOCK_WRLOCK = 6,
- /// The process associated with process descriptor
- /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated.
- PROC_TERMINATE = 7,
-}
-
-/// Exit code generated by a process when exiting.
-pub type exitcode = u32;
-
-/// A file descriptor number.
-///
-/// Unlike on POSIX-compliant systems, none of the file descriptor
-/// numbers are reserved for a purpose (e.g., stdin, stdout,
-/// stderr). Operating systems are not required to allocate new
-/// file descriptors in ascending order.
-#[repr(C)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct fd(pub u32);
-/// Returned to the child process by [`proc_fork()`](fn.proc_fork.html).
-pub const PROCESS_CHILD: fd = fd(0xffffffff);
-/// Passed to [`mem_map()`](fn.mem_map.html) when creating a mapping to
-/// anonymous memory.
-pub const MAP_ANON_FD: fd = fd(0xffffffff);
-
-bitflags! {
- /// File descriptor flags.
- #[repr(C)]
- pub struct fdflags: u16 {
- /// Append mode: Data written to the file is always
- /// appended to the file's end.
- const APPEND = 0x0001;
- /// Write according to synchronized I/O data integrity
- /// completion. Only the data stored in the file is
- /// synchronized.
- const DSYNC = 0x0002;
- /// Non-blocking mode.
- const NONBLOCK = 0x0004;
- /// Synchronized read I/O operations.
- const RSYNC = 0x0008;
- /// Write according to synchronized I/O file integrity
- /// completion. In addition to synchronizing the data
- /// stored in the file, the system may also synchronously
- /// update the file's metadata.
- const SYNC = 0x0010;
- }
-}
-
-bitflags! {
- /// Which file descriptor attributes to adjust.
- #[repr(C)]
- pub struct fdsflags: u16 {
- /// Adjust the file descriptor flags stored in
- /// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags).
- const FLAGS = 0x0001;
- /// Restrict the rights of the file descriptor to the
- /// rights stored in [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and
- /// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting).
- const RIGHTS = 0x0002;
- }
-}
-
-/// Relative offset within a file.
-pub type filedelta = i64;
-
-/// Non-negative file size or length of a region within a file.
-pub type filesize = u64;
-
-/// The type of a file descriptor or file.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum filetype {
- /// The type of the file descriptor or file is unknown or
- /// is different from any of the other types specified.
- UNKNOWN = 0,
- /// The file descriptor or file refers to a block device
- /// inode.
- BLOCK_DEVICE = 16,
- /// The file descriptor or file refers to a character
- /// device inode.
- CHARACTER_DEVICE = 17,
- /// The file descriptor or file refers to a directory
- /// inode.
- DIRECTORY = 32,
- /// The file descriptor refers to a process handle.
- PROCESS = 80,
- /// The file descriptor or file refers to a regular file
- /// inode.
- REGULAR_FILE = 96,
- /// The file descriptor refers to a shared memory object.
- SHARED_MEMORY = 112,
- /// The file descriptor or file refers to a datagram
- /// socket.
- SOCKET_DGRAM = 128,
- /// The file descriptor or file refers to a byte-stream
- /// socket.
- SOCKET_STREAM = 130,
- /// The file refers to a symbolic link inode.
- SYMBOLIC_LINK = 144,
-}
-
-bitflags! {
- /// Which file attributes to adjust.
- #[repr(C)]
- pub struct fsflags: u16 {
- /// Adjust the last data access timestamp to the value
- /// stored in [`filestat.st_atim`](struct.filestat.html#structfield.st_atim).
- const ATIM = 0x0001;
- /// Adjust the last data access timestamp to the time
- /// of clock [`REALTIME`](enum.clockid.html#variant.REALTIME).
- const ATIM_NOW = 0x0002;
- /// Adjust the last data modification timestamp to the
- /// value stored in [`filestat.st_mtim`](struct.filestat.html#structfield.st_mtim).
- const MTIM = 0x0004;
- /// Adjust the last data modification timestamp to the
- /// time of clock [`REALTIME`](enum.clockid.html#variant.REALTIME).
- const MTIM_NOW = 0x0008;
- /// Truncate or extend the file to the size stored in
- /// [`filestat.st_size`](struct.filestat.html#structfield.st_size).
- const SIZE = 0x0010;
- }
-}
-
-/// File serial number that is unique within its file system.
-#[repr(C)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct inode(pub u64);
-
-/// Number of hard links to an inode.
-pub type linkcount = u32;
-
-/// A userspace read-recursive readers-writer lock, similar to a
-/// Linux futex or a FreeBSD umtx.
-#[repr(C)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct lock(pub u32);
-/// Value indicating that the lock is in its initial
-/// unlocked state.
-pub const LOCK_UNLOCKED: lock = lock(0x00000000);
-/// Bitmask indicating that the lock is write-locked. If
-/// set, the lower 30 bits of the lock contain the
-/// identifier of the thread that owns the write lock.
-/// Otherwise, the lower 30 bits of the lock contain the
-/// number of acquired read locks.
-pub const LOCK_WRLOCKED: lock = lock(0x40000000);
-/// Bitmask indicating that the lock is either read locked
-/// or write locked, and that one or more threads have
-/// their execution suspended, waiting to acquire the
-/// lock. The last owner of the lock must call the
-/// kernel to unlock.
-///
-/// When the lock is acquired for reading and this bit is
-/// set, it means that one or more threads are attempting
-/// to acquire this lock for writing. In that case, other
-/// threads should only acquire additional read locks if
-/// suspending execution would cause a deadlock. It is
-/// preferred to suspend execution, as this prevents
-/// starvation of writers.
-pub const LOCK_KERNEL_MANAGED: lock = lock(0x80000000);
-/// Value indicating that the lock is in an incorrect
-/// state. A lock cannot be in its initial unlocked state,
-/// while also managed by the kernel.
-pub const LOCK_BOGUS: lock = lock(0x80000000);
-
-bitflags! {
- /// Flags determining the method of how paths are resolved.
- #[repr(C)]
- pub struct lookupflags: u32 {
- /// As long as the resolved path corresponds to a symbolic
- /// link, it is expanded.
- const SYMLINK_FOLLOW = 0x00000001;
- }
-}
-
-bitflags! {
- /// Memory mapping flags.
- #[repr(C)]
- pub struct mflags: u8 {
- /// Instead of mapping the contents of the file provided,
- /// create a mapping to anonymous memory. The file
- /// descriptor argument must be set to [`MAP_ANON_FD`](constant.MAP_ANON_FD.html),
- /// and the offset must be set to zero.
- const ANON = 0x01;
- /// Require that the mapping is performed at the base
- /// address provided.
- const FIXED = 0x02;
- /// Changes are private.
- const PRIVATE = 0x04;
- /// Changes are shared.
- const SHARED = 0x08;
- }
-}
-
-bitflags! {
- /// Memory page protection options.
- ///
- /// This implementation enforces the `W^X` property: Pages cannot be
- /// mapped for execution while also mapped for writing.
- #[repr(C)]
- pub struct mprot: u8 {
- /// Page can be executed.
- const EXEC = 0x01;
- /// Page can be written.
- const WRITE = 0x02;
- /// Page can be read.
- const READ = 0x04;
- }
-}
-
-bitflags! {
- /// Methods of synchronizing memory with physical storage.
- #[repr(C)]
- pub struct msflags: u8 {
- /// Performs asynchronous writes.
- const ASYNC = 0x01;
- /// Invalidates cached data.
- const INVALIDATE = 0x02;
- /// Performs synchronous writes.
- const SYNC = 0x04;
- }
-}
-
-/// Specifies the number of threads sleeping on a condition
-/// variable that should be woken up.
-pub type nthreads = u32;
-
-bitflags! {
- /// Open flags used by [`file_open()`](fn.file_open.html).
- #[repr(C)]
- pub struct oflags: u16 {
- /// Create file if it does not exist.
- const CREAT = 0x0001;
- /// Fail if not a directory.
- const DIRECTORY = 0x0002;
- /// Fail if file already exists.
- const EXCL = 0x0004;
- /// Truncate file to size 0.
- const TRUNC = 0x0008;
- }
-}
-
-bitflags! {
- /// Flags provided to [`sock_recv()`](fn.sock_recv.html).
- #[repr(C)]
- pub struct riflags: u16 {
- /// Returns the message without removing it from the
- /// socket's receive queue.
- const PEEK = 0x0004;
- /// On byte-stream sockets, block until the full amount
- /// of data can be returned.
- const WAITALL = 0x0010;
- }
-}
-
-bitflags! {
- /// File descriptor rights, determining which actions may be
- /// performed.
- #[repr(C)]
- pub struct rights: u64 {
- /// The right to invoke [`fd_datasync()`](fn.fd_datasync.html).
- ///
- /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
- /// invoke [`file_open()`](fn.file_open.html) with [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC).
- const FD_DATASYNC = 0x0000000000000001;
- /// The right to invoke [`fd_read()`](fn.fd_read.html) and [`sock_recv()`](fn.sock_recv.html).
- ///
- /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to
- /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option
- /// [`READ`](struct.mprot.html#associatedconstant.READ).
- ///
- /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to invoke
- /// [`fd_pread()`](fn.fd_pread.html).
- const FD_READ = 0x0000000000000002;
- /// The right to invoke [`fd_seek()`](fn.fd_seek.html). This flag implies
- /// [`FD_TELL`](struct.rights.html#associatedconstant.FD_TELL).
- const FD_SEEK = 0x0000000000000004;
- /// The right to invoke [`fd_stat_put()`](fn.fd_stat_put.html) with
- /// [`FLAGS`](struct.fdsflags.html#associatedconstant.FLAGS).
- const FD_STAT_PUT_FLAGS = 0x0000000000000008;
- /// The right to invoke [`fd_sync()`](fn.fd_sync.html).
- ///
- /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
- /// invoke [`file_open()`](fn.file_open.html) with [`RSYNC`](struct.fdflags.html#associatedconstant.RSYNC) and
- /// [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC).
- const FD_SYNC = 0x0000000000000010;
- /// The right to invoke [`fd_seek()`](fn.fd_seek.html) in such a way that the
- /// file offset remains unaltered (i.e., [`CUR`](enum.whence.html#variant.CUR) with
- /// offset zero).
- const FD_TELL = 0x0000000000000020;
- /// The right to invoke [`fd_write()`](fn.fd_write.html) and [`sock_send()`](fn.sock_send.html).
- ///
- /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to
- /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option
- /// [`WRITE`](struct.mprot.html#associatedconstant.WRITE).
- ///
- /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to
- /// invoke [`fd_pwrite()`](fn.fd_pwrite.html).
- const FD_WRITE = 0x0000000000000040;
- /// The right to invoke [`file_advise()`](fn.file_advise.html).
- const FILE_ADVISE = 0x0000000000000080;
- /// The right to invoke [`file_allocate()`](fn.file_allocate.html).
- const FILE_ALLOCATE = 0x0000000000000100;
- /// The right to invoke [`file_create()`](fn.file_create.html) with
- /// [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY).
- const FILE_CREATE_DIRECTORY = 0x0000000000000200;
- /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, the right to invoke
- /// [`file_open()`](fn.file_open.html) with [`CREAT`](struct.oflags.html#associatedconstant.CREAT).
- const FILE_CREATE_FILE = 0x0000000000000400;
- /// The right to invoke [`file_link()`](fn.file_link.html) with the file
- /// descriptor as the source directory.
- const FILE_LINK_SOURCE = 0x0000000000001000;
- /// The right to invoke [`file_link()`](fn.file_link.html) with the file
- /// descriptor as the target directory.
- const FILE_LINK_TARGET = 0x0000000000002000;
- /// The right to invoke [`file_open()`](fn.file_open.html).
- const FILE_OPEN = 0x0000000000004000;
- /// The right to invoke [`file_readdir()`](fn.file_readdir.html).
- const FILE_READDIR = 0x0000000000008000;
- /// The right to invoke [`file_readlink()`](fn.file_readlink.html).
- const FILE_READLINK = 0x0000000000010000;
- /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file
- /// descriptor as the source directory.
- const FILE_RENAME_SOURCE = 0x0000000000020000;
- /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file
- /// descriptor as the target directory.
- const FILE_RENAME_TARGET = 0x0000000000040000;
- /// The right to invoke [`file_stat_fget()`](fn.file_stat_fget.html).
- const FILE_STAT_FGET = 0x0000000000080000;
- /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with
- /// [`SIZE`](struct.fsflags.html#associatedconstant.SIZE).
- ///
- /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to
- /// invoke [`file_open()`](fn.file_open.html) with [`TRUNC`](struct.oflags.html#associatedconstant.TRUNC).
- const FILE_STAT_FPUT_SIZE = 0x0000000000100000;
- /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with
- /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM),
- /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW).
- const FILE_STAT_FPUT_TIMES = 0x0000000000200000;
- /// The right to invoke [`file_stat_get()`](fn.file_stat_get.html).
- const FILE_STAT_GET = 0x0000000000400000;
- /// The right to invoke [`file_stat_put()`](fn.file_stat_put.html) with
- /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM),
- /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW).
- const FILE_STAT_PUT_TIMES = 0x0000000000800000;
- /// The right to invoke [`file_symlink()`](fn.file_symlink.html).
- const FILE_SYMLINK = 0x0000000001000000;
- /// The right to invoke [`file_unlink()`](fn.file_unlink.html).
- const FILE_UNLINK = 0x0000000002000000;
- /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`] set to
- /// zero.
- const MEM_MAP = 0x0000000004000000;
- /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke
- /// [`mem_map()`](fn.mem_map.html) with [`EXEC`](struct.mprot.html#associatedconstant.EXEC).
- const MEM_MAP_EXEC = 0x0000000008000000;
- /// If [`FD_READ`](struct.rights.html#associatedconstant.FD_READ) is set, includes the right to
- /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_READ`](enum.eventtype.html#variant.FD_READ).
- ///
- /// If [`FD_WRITE`](struct.rights.html#associatedconstant.FD_WRITE) is set, includes the right to
- /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
- const POLL_FD_READWRITE = 0x0000000010000000;
- /// The right to invoke [`poll()`](fn.poll.html) to subscribe to
- /// [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
- const POLL_PROC_TERMINATE = 0x0000000040000000;
- /// The right to invoke [`proc_exec()`](fn.proc_exec.html).
- const PROC_EXEC = 0x0000000100000000;
- /// The right to invoke [`sock_shutdown()`](fn.sock_shutdown.html).
- const SOCK_SHUTDOWN = 0x0000008000000000;
- }
-}
-
-bitflags! {
- /// Flags returned by [`sock_recv()`](fn.sock_recv.html).
- #[repr(C)]
- pub struct roflags: u16 {
- /// Returned by [`sock_recv()`](fn.sock_recv.html): List of file descriptors
- /// has been truncated.
- const FDS_TRUNCATED = 0x0001;
- /// Returned by [`sock_recv()`](fn.sock_recv.html): Message data has been
- /// truncated.
- const DATA_TRUNCATED = 0x0008;
- }
-}
-
-/// Indicates whether an object is stored in private or shared
-/// memory.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum scope {
- /// The object is stored in private memory.
- PRIVATE = 4,
- /// The object is stored in shared memory.
- SHARED = 8,
-}
-
-bitflags! {
- /// Which channels on a socket need to be shut down.
- #[repr(C)]
- pub struct sdflags: u8 {
- /// Disables further receive operations.
- const RD = 0x01;
- /// Disables further send operations.
- const WR = 0x02;
- }
-}
-
-bitflags! {
- /// Flags provided to [`sock_send()`](fn.sock_send.html). As there are currently no flags
- /// defined, it must be set to zero.
- #[repr(C)]
- pub struct siflags: u16 {
- const DEFAULT = 0;
- }
-}
-
-/// Signal condition.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum signal {
- /// Process abort signal.
- ///
- /// Action: Terminates the process.
- ABRT = 1,
- /// Alarm clock.
- ///
- /// Action: Terminates the process.
- ALRM = 2,
- /// Access to an undefined portion of a memory object.
- ///
- /// Action: Terminates the process.
- BUS = 3,
- /// Child process terminated, stopped, or continued.
- ///
- /// Action: Ignored.
- CHLD = 4,
- /// Continue executing, if stopped.
- ///
- /// Action: Continues executing, if stopped.
- CONT = 5,
- /// Erroneous arithmetic operation.
- ///
- /// Action: Terminates the process.
- FPE = 6,
- /// Hangup.
- ///
- /// Action: Terminates the process.
- HUP = 7,
- /// Illegal instruction.
- ///
- /// Action: Terminates the process.
- ILL = 8,
- /// Terminate interrupt signal.
- ///
- /// Action: Terminates the process.
- INT = 9,
- /// Kill.
- ///
- /// Action: Terminates the process.
- KILL = 10,
- /// Write on a pipe with no one to read it.
- ///
- /// Action: Ignored.
- PIPE = 11,
- /// Terminal quit signal.
- ///
- /// Action: Terminates the process.
- QUIT = 12,
- /// Invalid memory reference.
- ///
- /// Action: Terminates the process.
- SEGV = 13,
- /// Stop executing.
- ///
- /// Action: Stops executing.
- STOP = 14,
- /// Bad system call.
- ///
- /// Action: Terminates the process.
- SYS = 15,
- /// Termination signal.
- ///
- /// Action: Terminates the process.
- TERM = 16,
- /// Trace/breakpoint trap.
- ///
- /// Action: Terminates the process.
- TRAP = 17,
- /// Terminal stop signal.
- ///
- /// Action: Stops executing.
- TSTP = 18,
- /// Background process attempting read.
- ///
- /// Action: Stops executing.
- TTIN = 19,
- /// Background process attempting write.
- ///
- /// Action: Stops executing.
- TTOU = 20,
- /// High bandwidth data is available at a socket.
- ///
- /// Action: Ignored.
- URG = 21,
- /// User-defined signal 1.
- ///
- /// Action: Terminates the process.
- USR1 = 22,
- /// User-defined signal 2.
- ///
- /// Action: Terminates the process.
- USR2 = 23,
- /// Virtual timer expired.
- ///
- /// Action: Terminates the process.
- VTALRM = 24,
- /// CPU time limit exceeded.
- ///
- /// Action: Terminates the process.
- XCPU = 25,
- /// File size limit exceeded.
- ///
- /// Action: Terminates the process.
- XFSZ = 26,
-}
-
-bitflags! {
- /// Flags determining how the timestamp provided in
- /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) should be interpreted.
- #[repr(C)]
- pub struct subclockflags: u16 {
- /// If set, treat the timestamp provided in
- /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) as an absolute timestamp
- /// of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id).
- ///
- /// If clear, treat the timestamp provided in
- /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) relative to the current
- /// time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id).
- const ABSTIME = 0x0001;
- }
-}
-
-bitflags! {
- /// Flags influencing the method of polling for read or writing on
- /// a file descriptor.
- #[repr(C)]
- pub struct subrwflags: u16 {
- /// Deprecated. Must be set by callers and ignored by
- /// implementations.
- const POLL = 0x0001;
- }
-}
-
-/// Unique system-local identifier of a thread. This identifier is
-/// only valid during the lifetime of the thread.
-///
-/// Threads must be aware of their thread identifier, as it is
-/// written it into locks when acquiring them for writing. It is
-/// not advised to use these identifiers for any other purpose.
-///
-/// As the thread identifier is also stored in [`lock`] when
-/// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread
-/// must always be set to zero.
-#[repr(C)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct tid(pub u32);
-
-/// Timestamp in nanoseconds.
-pub type timestamp = u64;
-
-bitflags! {
- /// Specifies whether files are unlinked or directories are
- /// removed.
- #[repr(C)]
- pub struct ulflags: u8 {
- /// If set, removes a directory. Otherwise, unlinks any
- /// non-directory file.
- const REMOVEDIR = 0x01;
- }
-}
-
-/// User-provided value that can be attached to objects that is
-/// retained when extracted from the kernel.
-pub type userdata = u64;
-
-/// Relative to which position the offset of the file descriptor
-/// should be set.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-#[non_exhaustive]
-pub enum whence {
- /// Seek relative to current position.
- CUR = 1,
- /// Seek relative to end-of-file.
- END = 2,
- /// Seek relative to start-of-file.
- SET = 3,
-}
-
-/// Auxiliary vector entry.
-///
-/// The auxiliary vector is a list of key-value pairs that is
-/// provided to the process on startup. Unlike structures, it is
-/// extensible, as it is possible to add new records later on.
-/// The auxiliary vector is always terminated by an entry having
-/// type [`NULL`](enum.auxtype.html#variant.NULL).
-///
-/// The auxiliary vector is part of the x86-64 ABI, but is used by
-/// this environment on all architectures.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct auxv {
- /// The type of the auxiliary vector entry.
- pub a_type: auxtype,
- pub union: auxv_union,
-}
-/// A union inside `auxv`.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union auxv_union {
- /// Used when `a_type` is [`ARGDATALEN`](enum.auxtype.html#variant.ARGDATALEN), [`CANARYLEN`](enum.auxtype.html#variant.CANARYLEN), [`NCPUS`](enum.auxtype.html#variant.NCPUS), [`PAGESZ`](enum.auxtype.html#variant.PAGESZ), [`PHNUM`](enum.auxtype.html#variant.PHNUM), or [`TID`](enum.auxtype.html#variant.TID).
- /// A numerical value.
- pub a_val: usize,
- /// Used when `a_type` is [`ARGDATA`](enum.auxtype.html#variant.ARGDATA), [`BASE`](enum.auxtype.html#variant.BASE), [`CANARY`](enum.auxtype.html#variant.CANARY), [`PHDR`](enum.auxtype.html#variant.PHDR), [`PID`](enum.auxtype.html#variant.PID), or [`SYSINFO_EHDR`](enum.auxtype.html#variant.SYSINFO_EHDR).
- /// A pointer value.
- pub a_ptr: *mut (),
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn auxv_layout_test_32() {
- assert_eq!(core::mem::size_of::<auxv>(), 8);
- assert_eq!(core::mem::align_of::<auxv>(), 4);
- unsafe {
- let obj: auxv = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.a_type as *const _ as usize - base, 0);
- assert_eq!(&obj.union.a_val as *const _ as usize - base, 4);
- assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 4);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn auxv_layout_test_64() {
- assert_eq!(core::mem::size_of::<auxv>(), 16);
- assert_eq!(core::mem::align_of::<auxv>(), 8);
- unsafe {
- let obj: auxv = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.a_type as *const _ as usize - base, 0);
- assert_eq!(&obj.union.a_val as *const _ as usize - base, 8);
- assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 8);
- }
-}
-
-/// A region of memory for scatter/gather writes.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct ciovec {
- /// The address and length of the buffer to be written.
- pub buf: (*const (), usize),
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn ciovec_layout_test_32() {
- assert_eq!(core::mem::size_of::<ciovec>(), 8);
- assert_eq!(core::mem::align_of::<ciovec>(), 4);
- unsafe {
- let obj: ciovec = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.buf.1 as *const _ as usize - base, 4);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn ciovec_layout_test_64() {
- assert_eq!(core::mem::size_of::<ciovec>(), 16);
- assert_eq!(core::mem::align_of::<ciovec>(), 8);
- unsafe {
- let obj: ciovec = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.buf.1 as *const _ as usize - base, 8);
- }
-}
-
-/// A directory entry.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct dirent {
- /// The offset of the next directory entry stored in this
- /// directory.
- pub d_next: dircookie,
- /// The serial number of the file referred to by this
- /// directory entry.
- pub d_ino: inode,
- /// The length of the name of the directory entry.
- pub d_namlen: u32,
- /// The type of the file referred to by this directory
- /// entry.
- pub d_type: filetype,
-}
-#[test]
-fn dirent_layout_test() {
- assert_eq!(core::mem::size_of::<dirent>(), 24);
- assert_eq!(core::mem::align_of::<dirent>(), 8);
- unsafe {
- let obj: dirent = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.d_next as *const _ as usize - base, 0);
- assert_eq!(&obj.d_ino as *const _ as usize - base, 8);
- assert_eq!(&obj.d_namlen as *const _ as usize - base, 16);
- assert_eq!(&obj.d_type as *const _ as usize - base, 20);
- }
-}
-
-/// An event that occurred.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct event {
- /// User-provided value that got attached to
- /// [`subscription.userdata`](struct.subscription.html#structfield.userdata).
- pub userdata: userdata,
- /// If non-zero, an error that occurred while processing
- /// the subscription request.
- pub error: errno,
- /// The type of the event that occurred.
- pub type_: eventtype,
- pub union: event_union,
-}
-/// A union inside `event`.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union event_union {
- /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
- pub fd_readwrite: event_fd_readwrite,
- /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
- pub proc_terminate: event_proc_terminate,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct event_fd_readwrite {
- /// The number of bytes available
- /// for reading or writing.
- pub nbytes: filesize,
- /// Obsolete.
- pub unused: [u8; 4],
- /// The state of the file
- /// descriptor.
- pub flags: eventrwflags,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct event_proc_terminate {
- /// Obsolete.
- pub unused: [u8; 4],
- /// If zero, the process has
- /// exited.
- /// Otherwise, the signal
- /// condition causing it to
- /// terminated.
- pub signal: signal,
- /// If exited, the exit code of
- /// the process.
- pub exitcode: exitcode,
-}
-#[test]
-fn event_layout_test() {
- assert_eq!(core::mem::size_of::<event>(), 32);
- assert_eq!(core::mem::align_of::<event>(), 8);
- unsafe {
- let obj: event = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.userdata as *const _ as usize - base, 0);
- assert_eq!(&obj.error as *const _ as usize - base, 8);
- assert_eq!(&obj.type_ as *const _ as usize - base, 10);
- assert_eq!(&obj.union.fd_readwrite.nbytes as *const _ as usize - base, 16);
- assert_eq!(&obj.union.fd_readwrite.unused as *const _ as usize - base, 24);
- assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 28);
- assert_eq!(&obj.union.proc_terminate.unused as *const _ as usize - base, 16);
- assert_eq!(&obj.union.proc_terminate.signal as *const _ as usize - base, 20);
- assert_eq!(&obj.union.proc_terminate.exitcode as *const _ as usize - base, 24);
- }
-}
-
-/// File descriptor attributes.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct fdstat {
- /// File type.
- pub fs_filetype: filetype,
- /// File descriptor flags.
- pub fs_flags: fdflags,
- /// Rights that apply to this file descriptor.
- pub fs_rights_base: rights,
- /// Maximum set of rights that can be installed on new
- /// file descriptors that are created through this file
- /// descriptor, e.g., through [`file_open()`](fn.file_open.html).
- pub fs_rights_inheriting: rights,
-}
-#[test]
-fn fdstat_layout_test() {
- assert_eq!(core::mem::size_of::<fdstat>(), 24);
- assert_eq!(core::mem::align_of::<fdstat>(), 8);
- unsafe {
- let obj: fdstat = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.fs_filetype as *const _ as usize - base, 0);
- assert_eq!(&obj.fs_flags as *const _ as usize - base, 2);
- assert_eq!(&obj.fs_rights_base as *const _ as usize - base, 8);
- assert_eq!(&obj.fs_rights_inheriting as *const _ as usize - base, 16);
- }
-}
-
-/// File attributes.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct filestat {
- /// Device ID of device containing the file.
- pub st_dev: device,
- /// File serial number.
- pub st_ino: inode,
- /// File type.
- pub st_filetype: filetype,
- /// Number of hard links to the file.
- pub st_nlink: linkcount,
- /// For regular files, the file size in bytes. For
- /// symbolic links, the length in bytes of the pathname
- /// contained in the symbolic link.
- pub st_size: filesize,
- /// Last data access timestamp.
- pub st_atim: timestamp,
- /// Last data modification timestamp.
- pub st_mtim: timestamp,
- /// Last file status change timestamp.
- pub st_ctim: timestamp,
-}
-#[test]
-fn filestat_layout_test() {
- assert_eq!(core::mem::size_of::<filestat>(), 56);
- assert_eq!(core::mem::align_of::<filestat>(), 8);
- unsafe {
- let obj: filestat = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.st_dev as *const _ as usize - base, 0);
- assert_eq!(&obj.st_ino as *const _ as usize - base, 8);
- assert_eq!(&obj.st_filetype as *const _ as usize - base, 16);
- assert_eq!(&obj.st_nlink as *const _ as usize - base, 20);
- assert_eq!(&obj.st_size as *const _ as usize - base, 24);
- assert_eq!(&obj.st_atim as *const _ as usize - base, 32);
- assert_eq!(&obj.st_mtim as *const _ as usize - base, 40);
- assert_eq!(&obj.st_ctim as *const _ as usize - base, 48);
- }
-}
-
-/// A region of memory for scatter/gather reads.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct iovec {
- /// The address and length of the buffer to be filled.
- pub buf: (*mut (), usize),
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn iovec_layout_test_32() {
- assert_eq!(core::mem::size_of::<iovec>(), 8);
- assert_eq!(core::mem::align_of::<iovec>(), 4);
- unsafe {
- let obj: iovec = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.buf.1 as *const _ as usize - base, 4);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn iovec_layout_test_64() {
- assert_eq!(core::mem::size_of::<iovec>(), 16);
- assert_eq!(core::mem::align_of::<iovec>(), 8);
- unsafe {
- let obj: iovec = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.buf.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.buf.1 as *const _ as usize - base, 8);
- }
-}
-
-/// Path lookup properties.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct lookup {
- /// The working directory at which the resolution of the
- /// path starts.
- pub fd: fd,
- /// Flags determining the method of how the path is
- /// resolved.
- pub flags: lookupflags,
-}
-#[test]
-fn lookup_layout_test() {
- assert_eq!(core::mem::size_of::<lookup>(), 8);
- assert_eq!(core::mem::align_of::<lookup>(), 4);
- unsafe {
- let obj: lookup = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.fd as *const _ as usize - base, 0);
- assert_eq!(&obj.flags as *const _ as usize - base, 4);
- }
-}
-
-/// Entry point for a process (`_start`).
-///
-/// **auxv**:
-/// The auxiliary vector. See [`auxv`].
-pub type processentry = unsafe extern "C" fn(auxv: *const auxv) -> ();
-
-/// Arguments of [`sock_recv()`](fn.sock_recv.html).
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct recv_in {
- /// List of scatter/gather vectors where message data
- /// should be stored.
- pub ri_data: (*const iovec, usize),
- /// Buffer where numbers of incoming file descriptors
- /// should be stored.
- pub ri_fds: (*mut fd, usize),
- /// Message flags.
- pub ri_flags: riflags,
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn recv_in_layout_test_32() {
- assert_eq!(core::mem::size_of::<recv_in>(), 20);
- assert_eq!(core::mem::align_of::<recv_in>(), 4);
- unsafe {
- let obj: recv_in = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 4);
- assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 8);
- assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 12);
- assert_eq!(&obj.ri_flags as *const _ as usize - base, 16);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn recv_in_layout_test_64() {
- assert_eq!(core::mem::size_of::<recv_in>(), 40);
- assert_eq!(core::mem::align_of::<recv_in>(), 8);
- unsafe {
- let obj: recv_in = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 8);
- assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 16);
- assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 24);
- assert_eq!(&obj.ri_flags as *const _ as usize - base, 32);
- }
-}
-
-/// Results of [`sock_recv()`](fn.sock_recv.html).
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct recv_out {
- /// Number of bytes stored in [`recv_in.ri_data`](struct.recv_in.html#structfield.ri_data).
- pub ro_datalen: usize,
- /// Number of file descriptors stored in [`recv_in.ri_fds`](struct.recv_in.html#structfield.ri_fds).
- pub ro_fdslen: usize,
- /// Fields that were used by previous implementations.
- pub ro_unused: [u8; 40],
- /// Message flags.
- pub ro_flags: roflags,
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn recv_out_layout_test_32() {
- assert_eq!(core::mem::size_of::<recv_out>(), 52);
- assert_eq!(core::mem::align_of::<recv_out>(), 4);
- unsafe {
- let obj: recv_out = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0);
- assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 4);
- assert_eq!(&obj.ro_unused as *const _ as usize - base, 8);
- assert_eq!(&obj.ro_flags as *const _ as usize - base, 48);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn recv_out_layout_test_64() {
- assert_eq!(core::mem::size_of::<recv_out>(), 64);
- assert_eq!(core::mem::align_of::<recv_out>(), 8);
- unsafe {
- let obj: recv_out = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0);
- assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 8);
- assert_eq!(&obj.ro_unused as *const _ as usize - base, 16);
- assert_eq!(&obj.ro_flags as *const _ as usize - base, 56);
- }
-}
-
-/// Arguments of [`sock_send()`](fn.sock_send.html).
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct send_in {
- /// List of scatter/gather vectors where message data
- /// should be retrieved.
- pub si_data: (*const ciovec, usize),
- /// File descriptors that need to be attached to the
- /// message.
- pub si_fds: (*const fd, usize),
- /// Message flags.
- pub si_flags: siflags,
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn send_in_layout_test_32() {
- assert_eq!(core::mem::size_of::<send_in>(), 20);
- assert_eq!(core::mem::align_of::<send_in>(), 4);
- unsafe {
- let obj: send_in = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.si_data.1 as *const _ as usize - base, 4);
- assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 8);
- assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 12);
- assert_eq!(&obj.si_flags as *const _ as usize - base, 16);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn send_in_layout_test_64() {
- assert_eq!(core::mem::size_of::<send_in>(), 40);
- assert_eq!(core::mem::align_of::<send_in>(), 8);
- unsafe {
- let obj: send_in = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0);
- assert_eq!(&obj.si_data.1 as *const _ as usize - base, 8);
- assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 16);
- assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 24);
- assert_eq!(&obj.si_flags as *const _ as usize - base, 32);
- }
-}
-
-/// Results of [`sock_send()`](fn.sock_send.html).
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct send_out {
- /// Number of bytes transmitted.
- pub so_datalen: usize,
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn send_out_layout_test_32() {
- assert_eq!(core::mem::size_of::<send_out>(), 4);
- assert_eq!(core::mem::align_of::<send_out>(), 4);
- unsafe {
- let obj: send_out = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.so_datalen as *const _ as usize - base, 0);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn send_out_layout_test_64() {
- assert_eq!(core::mem::size_of::<send_out>(), 8);
- assert_eq!(core::mem::align_of::<send_out>(), 8);
- unsafe {
- let obj: send_out = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.so_datalen as *const _ as usize - base, 0);
- }
-}
-
-/// Subscription to an event.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct subscription {
- /// User-provided value that is attached to the
- /// subscription in the kernel and returned through
- /// [`event.userdata`](struct.event.html#structfield.userdata).
- pub userdata: userdata,
- /// Used by previous implementations. Ignored.
- pub unused: u16,
- /// The type of the event to which to subscribe.
- ///
- /// Currently, [`CONDVAR`](enum.eventtype.html#variant.CONDVAR),
- /// [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK), and [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK)
- /// must be provided as the first subscription and may
- /// only be followed by up to one other subscription,
- /// having type [`CLOCK`](enum.eventtype.html#variant.CLOCK).
- pub type_: eventtype,
- pub union: subscription_union,
-}
-/// A union inside `subscription`.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union subscription_union {
- /// Used when `type_` is [`CLOCK`](enum.eventtype.html#variant.CLOCK).
- pub clock: subscription_clock,
- /// Used when `type_` is [`CONDVAR`](enum.eventtype.html#variant.CONDVAR).
- pub condvar: subscription_condvar,
- /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE).
- pub fd_readwrite: subscription_fd_readwrite,
- /// Used when `type_` is [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK) or [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK).
- pub lock: subscription_lock,
- /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE).
- pub proc_terminate: subscription_proc_terminate,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct subscription_clock {
- /// The user-defined unique
- /// identifier of the clock.
- pub identifier: userdata,
- /// The clock against which the
- /// timestamp should be compared.
- pub clock_id: clockid,
- /// The absolute or relative
- /// timestamp.
- pub timeout: timestamp,
- /// The amount of time that the
- /// kernel may wait additionally
- /// to coalesce with other events.
- pub precision: timestamp,
- /// Flags specifying whether the
- /// timeout is absolute or
- /// relative.
- pub flags: subclockflags,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct subscription_condvar {
- /// The condition variable on
- /// which to wait to be woken up.
- pub condvar: *mut condvar,
- /// The lock that will be
- /// released while waiting.
- ///
- /// The lock will be reacquired
- /// for writing when the condition
- /// variable triggers.
- pub lock: *mut lock,
- /// Whether the condition variable
- /// is stored in private or shared
- /// memory.
- pub condvar_scope: scope,
- /// Whether the lock is stored in
- /// private or shared memory.
- pub lock_scope: scope,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct subscription_fd_readwrite {
- /// The file descriptor on which
- /// to wait for it to become ready
- /// for reading or writing.
- pub fd: fd,
- /// Under which conditions to
- /// trigger.
- pub flags: subrwflags,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct subscription_lock {
- /// The lock that will be acquired
- /// for reading or writing.
- pub lock: *mut lock,
- /// Whether the lock is stored in
- /// private or shared memory.
- pub lock_scope: scope,
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct subscription_proc_terminate {
- /// The process descriptor on
- /// which to wait for process
- /// termination.
- pub fd: fd,
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn subscription_layout_test_32() {
- assert_eq!(core::mem::size_of::<subscription>(), 56);
- assert_eq!(core::mem::align_of::<subscription>(), 8);
- unsafe {
- let obj: subscription = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.userdata as *const _ as usize - base, 0);
- assert_eq!(&obj.unused as *const _ as usize - base, 8);
- assert_eq!(&obj.type_ as *const _ as usize - base, 10);
- assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16);
- assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24);
- assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32);
- assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40);
- assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48);
- assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16);
- assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 20);
- assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 24);
- assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 25);
- assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16);
- assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20);
- assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16);
- assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 20);
- assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn subscription_layout_test_64() {
- assert_eq!(core::mem::size_of::<subscription>(), 56);
- assert_eq!(core::mem::align_of::<subscription>(), 8);
- unsafe {
- let obj: subscription = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.userdata as *const _ as usize - base, 0);
- assert_eq!(&obj.unused as *const _ as usize - base, 8);
- assert_eq!(&obj.type_ as *const _ as usize - base, 10);
- assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16);
- assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24);
- assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32);
- assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40);
- assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48);
- assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16);
- assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 24);
- assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 32);
- assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 33);
- assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16);
- assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20);
- assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16);
- assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 24);
- assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16);
- }
-}
-
-/// The Thread Control Block (TCB).
-///
-/// After a thread begins execution (at program startup or when
-/// created through [`thread_create()`](fn.thread_create.html)), the CPU's registers
-/// controlling Thread-Local Storage (TLS) will already be
-/// initialized. They will point to an area only containing the
-/// TCB.
-///
-/// If the thread needs space for storing thread-specific
-/// variables, the thread may allocate a larger area and adjust
-/// the CPU's registers to point to that area instead. However, it
-/// does need to make sure that the TCB is copied over to the new
-/// TLS area.
-///
-/// The purpose of the TCB is that it allows light-weight
-/// emulators to store information related to individual threads.
-/// For example, it may be used to store a copy of the CPU
-/// registers prior emulation, so that TLS for the host system
-/// can be restored if needed.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct tcb {
- /// Pointer that may be freely assigned by the system. Its
- /// value cannot be interpreted by the application.
- pub parent: *mut (),
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn tcb_layout_test_32() {
- assert_eq!(core::mem::size_of::<tcb>(), 4);
- assert_eq!(core::mem::align_of::<tcb>(), 4);
- unsafe {
- let obj: tcb = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.parent as *const _ as usize - base, 0);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn tcb_layout_test_64() {
- assert_eq!(core::mem::size_of::<tcb>(), 8);
- assert_eq!(core::mem::align_of::<tcb>(), 8);
- unsafe {
- let obj: tcb = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.parent as *const _ as usize - base, 0);
- }
-}
-
-/// Entry point for additionally created threads.
-///
-/// `tid`: thread ID of the current thread.
-///
-/// `aux`: copy of the value stored in
-/// [`threadattr.argument`](struct.threadattr.html#structfield.argument).
-pub type threadentry = unsafe extern "C" fn(tid: tid, aux: *mut ()) -> ();
-
-/// Attributes for thread creation.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct threadattr {
- /// Initial program counter value.
- pub entry_point: threadentry,
- /// Region allocated to serve as stack space.
- pub stack: (*mut (), usize),
- /// Argument to be forwarded to the entry point function.
- pub argument: *mut (),
-}
-#[test]
-#[cfg(target_pointer_width = "32")]
-fn threadattr_layout_test_32() {
- assert_eq!(core::mem::size_of::<threadattr>(), 16);
- assert_eq!(core::mem::align_of::<threadattr>(), 4);
- unsafe {
- let obj: threadattr = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.entry_point as *const _ as usize - base, 0);
- assert_eq!(&obj.stack.0 as *const _ as usize - base, 4);
- assert_eq!(&obj.stack.1 as *const _ as usize - base, 8);
- assert_eq!(&obj.argument as *const _ as usize - base, 12);
- }
-}
-#[test]
-#[cfg(target_pointer_width = "64")]
-fn threadattr_layout_test_64() {
- assert_eq!(core::mem::size_of::<threadattr>(), 32);
- assert_eq!(core::mem::align_of::<threadattr>(), 8);
- unsafe {
- let obj: threadattr = core::mem::uninitialized();
- let base = &obj as *const _ as usize;
- assert_eq!(&obj.entry_point as *const _ as usize - base, 0);
- assert_eq!(&obj.stack.0 as *const _ as usize - base, 8);
- assert_eq!(&obj.stack.1 as *const _ as usize - base, 16);
- assert_eq!(&obj.argument as *const _ as usize - base, 24);
- }
-}
-
-/// The table with pointers to all syscall implementations.
-#[allow(improper_ctypes)]
-extern "C" {
- fn cloudabi_sys_clock_res_get(_: clockid, _: *mut timestamp) -> errno;
- fn cloudabi_sys_clock_time_get(_: clockid, _: timestamp, _: *mut timestamp) -> errno;
- fn cloudabi_sys_condvar_signal(_: *mut condvar, _: scope, _: nthreads) -> errno;
- fn cloudabi_sys_fd_close(_: fd) -> errno;
- fn cloudabi_sys_fd_create1(_: filetype, _: *mut fd) -> errno;
- fn cloudabi_sys_fd_create2(_: filetype, _: *mut fd, _: *mut fd) -> errno;
- fn cloudabi_sys_fd_datasync(_: fd) -> errno;
- fn cloudabi_sys_fd_dup(_: fd, _: *mut fd) -> errno;
- fn cloudabi_sys_fd_pread(_: fd, _: *const iovec, _: usize, _: filesize, _: *mut usize)
- -> errno;
- fn cloudabi_sys_fd_pwrite(
- _: fd,
- _: *const ciovec,
- _: usize,
- _: filesize,
- _: *mut usize,
- ) -> errno;
- fn cloudabi_sys_fd_read(_: fd, _: *const iovec, _: usize, _: *mut usize) -> errno;
- fn cloudabi_sys_fd_replace(_: fd, _: fd) -> errno;
- fn cloudabi_sys_fd_seek(_: fd, _: filedelta, _: whence, _: *mut filesize) -> errno;
- fn cloudabi_sys_fd_stat_get(_: fd, _: *mut fdstat) -> errno;
- fn cloudabi_sys_fd_stat_put(_: fd, _: *const fdstat, _: fdsflags) -> errno;
- fn cloudabi_sys_fd_sync(_: fd) -> errno;
- fn cloudabi_sys_fd_write(_: fd, _: *const ciovec, _: usize, _: *mut usize) -> errno;
- fn cloudabi_sys_file_advise(_: fd, _: filesize, _: filesize, _: advice) -> errno;
- fn cloudabi_sys_file_allocate(_: fd, _: filesize, _: filesize) -> errno;
- fn cloudabi_sys_file_create(_: fd, _: *const u8, _: usize, _: filetype) -> errno;
- fn cloudabi_sys_file_link(
- _: lookup,
- _: *const u8,
- _: usize,
- _: fd,
- _: *const u8,
- _: usize,
- ) -> errno;
- fn cloudabi_sys_file_open(
- _: lookup,
- _: *const u8,
- _: usize,
- _: oflags,
- _: *const fdstat,
- _: *mut fd,
- ) -> errno;
- fn cloudabi_sys_file_readdir(_: fd, _: *mut (), _: usize, _: dircookie, _: *mut usize)
- -> errno;
- fn cloudabi_sys_file_readlink(
- _: fd,
- _: *const u8,
- _: usize,
- _: *mut u8,
- _: usize,
- _: *mut usize,
- ) -> errno;
- fn cloudabi_sys_file_rename(
- _: fd,
- _: *const u8,
- _: usize,
- _: fd,
- _: *const u8,
- _: usize,
- ) -> errno;
- fn cloudabi_sys_file_stat_fget(_: fd, _: *mut filestat) -> errno;
- fn cloudabi_sys_file_stat_fput(_: fd, _: *const filestat, _: fsflags) -> errno;
- fn cloudabi_sys_file_stat_get(_: lookup, _: *const u8, _: usize, _: *mut filestat) -> errno;
- fn cloudabi_sys_file_stat_put(
- _: lookup,
- _: *const u8,
- _: usize,
- _: *const filestat,
- _: fsflags,
- ) -> errno;
- fn cloudabi_sys_file_symlink(_: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno;
- fn cloudabi_sys_file_unlink(_: fd, _: *const u8, _: usize, _: ulflags) -> errno;
- fn cloudabi_sys_lock_unlock(_: *mut lock, _: scope) -> errno;
- fn cloudabi_sys_mem_advise(_: *mut (), _: usize, _: advice) -> errno;
- fn cloudabi_sys_mem_map(
- _: *mut (),
- _: usize,
- _: mprot,
- _: mflags,
- _: fd,
- _: filesize,
- _: *mut *mut (),
- ) -> errno;
- fn cloudabi_sys_mem_protect(_: *mut (), _: usize, _: mprot) -> errno;
- fn cloudabi_sys_mem_sync(_: *mut (), _: usize, _: msflags) -> errno;
- fn cloudabi_sys_mem_unmap(_: *mut (), _: usize) -> errno;
- fn cloudabi_sys_poll(_: *const subscription, _: *mut event, _: usize, _: *mut usize) -> errno;
- fn cloudabi_sys_proc_exec(_: fd, _: *const (), _: usize, _: *const fd, _: usize) -> errno;
- fn cloudabi_sys_proc_exit(_: exitcode) -> !;
- fn cloudabi_sys_proc_fork(_: *mut fd, _: *mut tid) -> errno;
- fn cloudabi_sys_proc_raise(_: signal) -> errno;
- fn cloudabi_sys_random_get(_: *mut (), _: usize) -> errno;
- fn cloudabi_sys_sock_recv(_: fd, _: *const recv_in, _: *mut recv_out) -> errno;
- fn cloudabi_sys_sock_send(_: fd, _: *const send_in, _: *mut send_out) -> errno;
- fn cloudabi_sys_sock_shutdown(_: fd, _: sdflags) -> errno;
- fn cloudabi_sys_thread_create(_: *mut threadattr, _: *mut tid) -> errno;
- fn cloudabi_sys_thread_exit(_: *mut lock, _: scope) -> !;
- fn cloudabi_sys_thread_yield() -> errno;
-}
-
-/// Obtains the resolution of a clock.
-///
-/// ## Parameters
-///
-/// **clock_id**:
-/// The clock for which the resolution needs to be
-/// returned.
-///
-/// **resolution**:
-/// The resolution of the clock.
-#[inline]
-pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno {
- unsafe { cloudabi_sys_clock_res_get(clock_id_, resolution_) }
-}
-
-/// Obtains the time value of a clock.
-///
-/// ## Parameters
-///
-/// **clock_id**:
-/// The clock for which the time needs to be
-/// returned.
-///
-/// **precision**:
-/// The maximum lag (exclusive) that the returned
-/// time value may have, compared to its actual
-/// value.
-///
-/// **time**:
-/// The time value of the clock.
-#[inline]
-pub unsafe fn clock_time_get(
- clock_id_: clockid,
- precision_: timestamp,
- time_: *mut timestamp,
-) -> errno {
- unsafe { cloudabi_sys_clock_time_get(clock_id_, precision_, time_) }
-}
-
-/// Wakes up threads waiting on a userspace condition variable.
-///
-/// If an invocation of this system call causes all waiting
-/// threads to be woken up, the value of the condition variable
-/// is set to [`CONDVAR_HAS_NO_WAITERS`](constant.CONDVAR_HAS_NO_WAITERS.html). As long as the condition
-/// variable is set to this value, it is not needed to invoke this
-/// system call.
-///
-/// ## Parameters
-///
-/// **condvar**:
-/// The userspace condition variable that has
-/// waiting threads.
-///
-/// **scope**:
-/// Whether the condition variable is stored in
-/// private or shared memory.
-///
-/// **nwaiters**:
-/// The number of threads that need to be woken
-/// up. If it exceeds the number of waiting
-/// threads, all threads are woken up.
-#[inline]
-pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno {
- unsafe { cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_) }
-}
-
-/// Closes a file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor that needs to be closed.
-#[inline]
-pub unsafe fn fd_close(fd_: fd) -> errno {
- unsafe { cloudabi_sys_fd_close(fd_) }
-}
-
-/// Creates a file descriptor.
-///
-/// ## Parameters
-///
-/// **type**:
-/// Possible values:
-///
-/// - [`SHARED_MEMORY`](enum.filetype.html#variant.SHARED_MEMORY):
-/// Creates an anonymous shared memory
-/// object.
-///
-/// **fd**:
-/// The file descriptor that has been created.
-#[inline]
-pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno {
- unsafe { cloudabi_sys_fd_create1(type_, fd_) }
-}
-
-/// Creates a pair of file descriptors.
-///
-/// ## Parameters
-///
-/// **type**:
-/// Possible values:
-///
-/// - [`SOCKET_DGRAM`](enum.filetype.html#variant.SOCKET_DGRAM):
-/// Creates a UNIX datagram socket pair.
-/// - [`SOCKET_STREAM`](enum.filetype.html#variant.SOCKET_STREAM):
-/// Creates a UNIX byte-stream socket
-/// pair.
-///
-/// **fd1**:
-/// The first file descriptor of the pair.
-///
-/// **fd2**:
-/// The second file descriptor of the pair.
-#[inline]
-pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno {
- // SAFETY: the caller must uphold the safety contract for `cloudabi_sys_fd_create2`.
- unsafe { cloudabi_sys_fd_create2(type_, fd1_, fd2_) }
-}
-
-/// Synchronizes the data of a file to disk.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor of the file whose data
-/// needs to be synchronized to disk.
-#[inline]
-pub unsafe fn fd_datasync(fd_: fd) -> errno {
- // SAFETY: the caller must guarantee that `fd` is valid
- // for synchronization.
- unsafe { cloudabi_sys_fd_datasync(fd_) }
-}
-
-/// Duplicates a file descriptor.
-///
-/// ## Parameters
-///
-/// **from**:
-/// The file descriptor that needs to be
-/// duplicated.
-///
-/// **fd**:
-/// The new file descriptor.
-#[inline]
-pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno {
- unsafe { cloudabi_sys_fd_dup(from_, fd_) }
-}
-
-/// Reads from a file descriptor, without using and updating the
-/// file descriptor's offset.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor from which data should be
-/// read.
-///
-/// **iovs**:
-/// List of scatter/gather vectors where data
-/// should be stored.
-///
-/// **offset**:
-/// The offset within the file at which reading
-/// should start.
-///
-/// **nread**:
-/// The number of bytes read.
-#[inline]
-pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno {
- unsafe { cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_) }
-}
-
-/// Writes to a file descriptor, without using and updating the
-/// file descriptor's offset.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor to which data should be
-/// written.
-///
-/// **iovs**:
-/// List of scatter/gather vectors where data
-/// should be retrieved.
-///
-/// **offset**:
-/// The offset within the file at which writing
-/// should start.
-///
-/// **nwritten**:
-/// The number of bytes written.
-#[inline]
-pub unsafe fn fd_pwrite(
- fd_: fd,
- iovs_: &[ciovec],
- offset_: filesize,
- nwritten_: &mut usize,
-) -> errno {
- unsafe { cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_) }
-}
-
-/// Reads from a file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor from which data should be
-/// read.
-///
-/// **iovs**:
-/// List of scatter/gather vectors where data
-/// should be stored.
-///
-/// **nread**:
-/// The number of bytes read.
-#[inline]
-pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno {
- unsafe { cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_) }
-}
-
-/// Atomically replaces a file descriptor by a copy of another
-/// file descriptor.
-///
-/// Due to the strong focus on thread safety, this environment
-/// does not provide a mechanism to duplicate a file descriptor to
-/// an arbitrary number, like dup2(). This would be prone to race
-/// conditions, as an actual file descriptor with the same number
-/// could be allocated by a different thread at the same time.
-///
-/// This system call provides a way to atomically replace file
-/// descriptors, which would disappear if dup2() were to be
-/// removed entirely.
-///
-/// ## Parameters
-///
-/// **from**:
-/// The file descriptor that needs to be copied.
-///
-/// **to**:
-/// The file descriptor that needs to be
-/// overwritten.
-#[inline]
-pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno {
- unsafe { cloudabi_sys_fd_replace(from_, to_) }
-}
-
-/// Moves the offset of the file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor whose offset has to be
-/// moved.
-///
-/// **offset**:
-/// The number of bytes to move.
-///
-/// **whence**:
-/// Relative to which position the move should
-/// take place.
-///
-/// **newoffset**:
-/// The new offset of the file descriptor,
-/// relative to the start of the file.
-#[inline]
-pub unsafe fn fd_seek(
- fd_: fd,
- offset_: filedelta,
- whence_: whence,
- newoffset_: &mut filesize,
-) -> errno {
- unsafe { cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) }
-}
-
-/// Gets attributes of a file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor whose attributes have to
-/// be obtained.
-///
-/// **buf**:
-/// The buffer where the file descriptor's
-/// attributes are stored.
-#[inline]
-pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
- unsafe { cloudabi_sys_fd_stat_get(fd_, buf_) }
-}
-
-/// Adjusts attributes of a file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor whose attributes have to
-/// be adjusted.
-///
-/// **buf**:
-/// The desired values of the file descriptor
-/// attributes that are adjusted.
-///
-/// **flags**:
-/// A bitmask indicating which attributes have to
-/// be adjusted.
-#[inline]
-pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno {
- unsafe { cloudabi_sys_fd_stat_put(fd_, buf_, flags_) }
-}
-
-/// Synchronizes the data and metadata of a file to disk.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor of the file whose data
-/// and metadata needs to be synchronized to disk.
-#[inline]
-pub unsafe fn fd_sync(fd_: fd) -> errno {
- unsafe { cloudabi_sys_fd_sync(fd_) }
-}
-
-/// Writes to a file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor to which data should be
-/// written.
-///
-/// **iovs**:
-/// List of scatter/gather vectors where data
-/// should be retrieved.
-///
-/// **nwritten**:
-/// The number of bytes written.
-#[inline]
-pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno {
- unsafe { cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_) }
-}
-
-/// Provides file advisory information on a file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor for which to provide file
-/// advisory information.
-///
-/// **offset**:
-/// The offset within the file to which the
-/// advisory applies.
-///
-/// **len**:
-/// The length of the region to which the advisory
-/// applies.
-///
-/// **advice**:
-/// The advice.
-#[inline]
-pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno {
- unsafe { cloudabi_sys_file_advise(fd_, offset_, len_, advice_) }
-}
-
-/// Forces the allocation of space in a file.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file in which the space should be
-/// allocated.
-///
-/// **offset**:
-/// The offset at which the allocation should
-/// start.
-///
-/// **len**:
-/// The length of the area that is allocated.
-#[inline]
-pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno {
- unsafe { cloudabi_sys_file_allocate(fd_, offset_, len_) }
-}
-
-/// Creates a file of a specified type.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The working directory at which the resolution
-/// of the file to be created starts.
-///
-/// **path**:
-/// The path at which the file should be created.
-///
-/// **type**:
-/// Possible values:
-///
-/// - [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY):
-/// Creates a directory.
-#[inline]
-pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
- unsafe { cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)}
-}
-
-/// Creates a hard link.
-///
-/// ## Parameters
-///
-/// **fd1**:
-/// The working directory at which the resolution
-/// of the source path starts.
-///
-/// **path1**:
-/// The source path of the file that should be
-/// hard linked.
-///
-/// **fd2**:
-/// The working directory at which the resolution
-/// of the destination path starts.
-///
-/// **path2**:
-/// The destination path at which the hard link
-/// should be created.
-#[inline]
-pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
- unsafe { cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) }
-}
-
-/// Opens a file.
-///
-/// ## Parameters
-///
-/// **dirfd**:
-/// The working directory at which the resolution
-/// of the file to be opened starts.
-///
-/// **path**:
-/// The path of the file that should be opened.
-///
-/// **oflags**:
-/// The method at which the file should be opened.
-///
-/// **fds**:
-/// [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and
-/// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting) specify the
-/// initial rights of the newly created file
-/// descriptor. The operating system is allowed to
-/// return a file descriptor with fewer rights
-/// than specified, if and only if those rights do
-/// not apply to the type of file being opened.
-///
-/// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags) specifies the initial flags
-/// of the file descriptor.
-///
-/// [`fdstat.fs_filetype`](struct.fdstat.html#structfield.fs_filetype) is ignored.
-///
-/// **fd**:
-/// The file descriptor of the file that has been
-/// opened.
-#[inline]
-pub unsafe fn file_open(
- dirfd_: lookup,
- path_: &[u8],
- oflags_: oflags,
- fds_: *const fdstat,
- fd_: &mut fd,
-) -> errno {
- unsafe { cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_) }
-}
-
-/// Reads directory entries from a directory.
-///
-/// When successful, the contents of the output buffer consist of
-/// a sequence of directory entries. Each directory entry consists
-/// of a [`dirent`] object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes
-/// holding the name of the directory entry.
-///
-/// This system call fills the output buffer as much as possible,
-/// potentially truncating the last directory entry. This allows
-/// the caller to grow its read buffer size in case it's too small
-/// to fit a single large directory entry, or skip the oversized
-/// directory entry.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The directory from which to read the directory
-/// entries.
-///
-/// **buf**:
-/// The buffer where directory entries are stored.
-///
-/// **cookie**:
-/// The location within the directory to start
-/// reading.
-///
-/// **bufused**:
-/// The number of bytes stored in the read buffer.
-/// If less than the size of the read buffer, the
-/// end of the directory has been reached.
-#[inline]
-pub unsafe fn file_readdir(
- fd_: fd,
- buf_: &mut [u8],
- cookie_: dircookie,
- bufused_: &mut usize,
-) -> errno {
- unsafe { cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_) }
-}
-
-/// Reads the contents of a symbolic link.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The working directory at which the resolution
-/// of the path of the symbolic starts.
-///
-/// **path**:
-/// The path of the symbolic link whose contents
-/// should be read.
-///
-/// **buf**:
-/// The buffer where the contents of the symbolic
-/// link should be stored.
-///
-/// **bufused**:
-/// The number of bytes placed in the buffer.
-#[inline]
-pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno {
- unsafe {
- cloudabi_sys_file_readlink(
- fd_,
- path_.as_ptr(),
- path_.len(),
- buf_.as_mut_ptr(),
- buf_.len(),
- bufused_,
- )
- }
-}
-
-/// Renames a file.
-///
-/// ## Parameters
-///
-/// **fd1**:
-/// The working directory at which the resolution
-/// of the source path starts.
-///
-/// **path1**:
-/// The source path of the file that should be
-/// renamed.
-///
-/// **fd2**:
-/// The working directory at which the resolution
-/// of the destination path starts.
-///
-/// **path2**:
-/// The destination path to which the file should
-/// be renamed.
-#[inline]
-pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
- unsafe {
- cloudabi_sys_file_rename(
- fd1_,
- path1_.as_ptr(),
- path1_.len(),
- fd2_,
- path2_.as_ptr(),
- path2_.len(),
- )
- }
-}
-
-/// Gets attributes of a file by file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor whose attributes have to
-/// be obtained.
-///
-/// **buf**:
-/// The buffer where the file's attributes are
-/// stored.
-#[inline]
-pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno {
- unsafe { cloudabi_sys_file_stat_fget(fd_, buf_) }
-}
-
-/// Adjusts attributes of a file by file descriptor.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The file descriptor whose attributes have to
-/// be adjusted.
-///
-/// **buf**:
-/// The desired values of the file attributes that
-/// are adjusted.
-///
-/// **flags**:
-/// A bitmask indicating which attributes have to
-/// be adjusted.
-#[inline]
-pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno {
- unsafe { cloudabi_sys_file_stat_fput(fd_, buf_, flags_) }
-}
-
-/// Gets attributes of a file by path.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The working directory at which the resolution
-/// of the path whose attributes have to be
-/// obtained starts.
-///
-/// **path**:
-/// The path of the file whose attributes have to
-/// be obtained.
-///
-/// **buf**:
-/// The buffer where the file's attributes are
-/// stored.
-#[inline]
-pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno {
- unsafe { cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_) }
-}
-
-/// Adjusts attributes of a file by path.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The working directory at which the resolution
-/// of the path whose attributes have to be
-/// adjusted starts.
-///
-/// **path**:
-/// The path of the file whose attributes have to
-/// be adjusted.
-///
-/// **buf**:
-/// The desired values of the file attributes that
-/// are adjusted.
-///
-/// **flags**:
-/// A bitmask indicating which attributes have to
-/// be adjusted.
-#[inline]
-pub unsafe fn file_stat_put(
- fd_: lookup,
- path_: &[u8],
- buf_: *const filestat,
- flags_: fsflags,
-) -> errno {
- unsafe { cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_) }
-}
-
-/// Creates a symbolic link.
-///
-/// ## Parameters
-///
-/// **path1**:
-/// The contents of the symbolic link.
-///
-/// **fd**:
-/// The working directory at which the resolution
-/// of the destination path starts.
-///
-/// **path2**:
-/// The destination path at which the symbolic
-/// link should be created.
-#[inline]
-pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno {
- unsafe { cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len()) }
-}
-
-/// Unlinks a file, or removes a directory.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// The working directory at which the resolution
-/// of the path starts.
-///
-/// **path**:
-/// The path that needs to be unlinked or removed.
-///
-/// **flags**:
-/// Possible values:
-///
-/// - [`REMOVEDIR`](struct.ulflags.html#associatedconstant.REMOVEDIR):
-/// If set, attempt to remove a directory.
-/// Otherwise, unlink a file.
-#[inline]
-pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
- unsafe { cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_) }
-}
-
-/// Unlocks a write-locked userspace lock.
-///
-/// If a userspace lock is unlocked while having its
-/// [`LOCK_KERNEL_MANAGED`](constant.LOCK_KERNEL_MANAGED.html) flag set, the lock cannot be unlocked in
-/// userspace directly. This system call needs to be performed
-/// instead, so that any waiting threads can be woken up.
-///
-/// To prevent spurious invocations of this system call, the lock
-/// must be locked for writing. This prevents other threads from
-/// acquiring additional read locks while the system call is in
-/// progress. If the lock is acquired for reading, it must first
-/// be upgraded to a write lock.
-///
-/// ## Parameters
-///
-/// **lock**:
-/// The userspace lock that is locked for writing
-/// by the calling thread.
-///
-/// **scope**:
-/// Whether the lock is stored in private or
-/// shared memory.
-#[inline]
-pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno {
- unsafe { cloudabi_sys_lock_unlock(lock_, scope_) }
-}
-
-/// Provides memory advisory information on a region of memory.
-///
-/// ## Parameters
-///
-/// **mapping**:
-/// The pages for which to provide memory advisory
-/// information.
-///
-/// **advice**:
-/// The advice.
-#[inline]
-pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno {
- unsafe { cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_) }
-}
-
-/// Creates a memory mapping, making the contents of a file
-/// accessible through memory.
-///
-/// ## Parameters
-///
-/// **addr**:
-/// If [`FIXED`](struct.mflags.html#associatedconstant.FIXED) is set, specifies to which
-/// address the file region is mapped. Otherwise,
-/// the mapping is performed at an unused
-/// location.
-///
-/// **len**:
-/// The length of the memory mapping to be
-/// created.
-///
-/// **prot**:
-/// Initial memory protection options for the
-/// memory mapping.
-///
-/// **flags**:
-/// Memory mapping flags.
-///
-/// **fd**:
-/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be
-/// [`MAP_ANON_FD`](constant.MAP_ANON_FD.html). Otherwise, this argument
-/// specifies the file whose contents need to be
-/// mapped.
-///
-/// **off**:
-/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be
-/// zero. Otherwise, this argument specifies the
-/// offset within the file at which the mapping
-/// starts.
-///
-/// **mem**:
-/// The starting address of the memory mapping.
-#[inline]
-pub unsafe fn mem_map(
- addr_: *mut (),
- len_: usize,
- prot_: mprot,
- flags_: mflags,
- fd_: fd,
- off_: filesize,
- mem_: &mut *mut (),
-) -> errno {
- unsafe { cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_) }
-}
-
-/// Changes the protection of a memory mapping.
-///
-/// ## Parameters
-///
-/// **mapping**:
-/// The pages that need their protection changed.
-///
-/// **prot**:
-/// New protection options.
-#[inline]
-pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno {
- unsafe { cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_) }
-}
-
-/// Synchronizes a region of memory with its physical storage.
-///
-/// ## Parameters
-///
-/// **mapping**:
-/// The pages that need to be synchronized.
-///
-/// **flags**:
-/// The method of synchronization.
-#[inline]
-pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno {
- unsafe { cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_) }
-}
-
-/// Unmaps a region of memory.
-///
-/// ## Parameters
-///
-/// **mapping**:
-/// The pages that needs to be unmapped.
-#[inline]
-pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno {
- unsafe { cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len()) }
-}
-
-/// Concurrently polls for the occurrence of a set of events.
-///
-/// ## Parameters
-///
-/// **in**:
-/// The events to which to subscribe.
-///
-/// **out**:
-/// The events that have occurred.
-///
-/// **nsubscriptions**:
-/// Both the number of subscriptions and events.
-///
-/// **nevents**:
-/// The number of events stored.
-#[inline]
-pub unsafe fn poll(
- in_: *const subscription,
- out_: *mut event,
- nsubscriptions_: usize,
- nevents_: *mut usize,
-) -> errno {
- unsafe { cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) }
-}
-
-/// Replaces the process by a new executable.
-///
-/// Process execution in CloudABI differs from POSIX in two ways:
-/// handling of arguments and inheritance of file descriptors.
-///
-/// CloudABI does not use string command line arguments. Instead,
-/// a buffer with binary data is copied into the address space of
-/// the new executable. The kernel does not enforce any specific
-/// structure to this data, although CloudABI's C library uses it
-/// to store a tree structure that is semantically identical to
-/// YAML.
-///
-/// Due to the strong focus on thread safety, file descriptors
-/// aren't inherited through close-on-exec flags. An explicit
-/// list of file descriptors that need to be retained needs to be
-/// provided. After execution, file descriptors are placed in the
-/// order in which they are stored in the array. This not only
-/// makes the execution process deterministic. It also prevents
-/// potential information disclosures about the layout of the
-/// original process.
-///
-/// ## Parameters
-///
-/// **fd**:
-/// A file descriptor of the new executable.
-///
-/// **data**:
-/// Binary argument data that is passed on to the
-/// new executable.
-///
-/// **fds**:
-/// The layout of the file descriptor table after
-/// execution.
-#[inline]
-pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno {
- unsafe { cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len()) }
-}
-
-/// Terminates the process normally.
-///
-/// ## Parameters
-///
-/// **rval**:
-/// The exit code returned by the process. The
-/// exit code can be obtained by other processes
-/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode).
-#[inline]
-pub unsafe fn proc_exit(rval_: exitcode) -> ! {
- unsafe { cloudabi_sys_proc_exit(rval_) }
-}
-
-/// Forks the process of the calling thread.
-///
-/// After forking, a new process shall be created, having only a
-/// copy of the calling thread. The parent process will obtain a
-/// process descriptor. When closed, the child process is
-/// automatically signaled with [`KILL`](enum.signal.html#variant.KILL).
-///
-/// ## Parameters
-///
-/// **fd**:
-/// In the parent process: the file descriptor
-/// number of the process descriptor.
-///
-/// In the child process: [`PROCESS_CHILD`](constant.PROCESS_CHILD.html).
-///
-/// **tid**:
-/// In the parent process: undefined.
-///
-/// In the child process: the thread ID of the
-/// initial thread of the child process.
-#[inline]
-pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno {
- unsafe { cloudabi_sys_proc_fork(fd_, tid_) }
-}
-
-/// Sends a signal to the process of the calling thread.
-///
-/// ## Parameters
-///
-/// **sig**:
-/// The signal condition that should be triggered.
-/// If the signal causes the process to terminate,
-/// its condition can be obtained by other
-/// processes through
-/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal).
-#[inline]
-pub unsafe fn proc_raise(sig_: signal) -> errno {
- unsafe { cloudabi_sys_proc_raise(sig_) }
-}
-
-/// Obtains random data from the kernel random number generator.
-///
-/// As this interface is not guaranteed to be fast, it is advised
-/// that the random data obtained through this system call is used
-/// as the seed for a userspace pseudo-random number generator.
-///
-/// ## Parameters
-///
-/// **buf**:
-/// The buffer that needs to be filled with random
-/// data.
-#[inline]
-pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
- unsafe { cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len()) }
-}
-
-/// Receives a message on a socket.
-///
-/// ## Parameters
-///
-/// **sock**:
-/// The socket on which a message should be
-/// received.
-///
-/// **in**:
-/// Input parameters.
-///
-/// **out**:
-/// Output parameters.
-#[inline]
-pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno {
- unsafe { cloudabi_sys_sock_recv(sock_, in_, out_) }
-}
-
-/// Sends a message on a socket.
-///
-/// ## Parameters
-///
-/// **sock**:
-/// The socket on which a message should be sent.
-///
-/// **in**:
-/// Input parameters.
-///
-/// **out**:
-/// Output parameters.
-#[inline]
-pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno {
- unsafe { cloudabi_sys_sock_send(sock_, in_, out_) }
-}
-
-/// Shuts down socket send and receive channels.
-///
-/// ## Parameters
-///
-/// **sock**:
-/// The socket that needs its channels shut down.
-///
-/// **how**:
-/// Which channels on the socket need to be shut
-/// down.
-#[inline]
-pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno {
- unsafe { cloudabi_sys_sock_shutdown(sock_, how_) }
-}
-
-/// Creates a new thread within the current process.
-///
-/// ## Parameters
-///
-/// **attr**:
-/// The desired attributes of the new thread.
-///
-/// **tid**:
-/// The thread ID of the new thread.
-#[inline]
-pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
- unsafe { cloudabi_sys_thread_create(attr_, tid_) }
-}
-
-/// Terminates the calling thread.
-///
-/// This system call can also unlock a single userspace lock
-/// after termination, which can be used to implement thread
-/// joining.
-///
-/// ## Parameters
-///
-/// **lock**:
-/// Userspace lock that is locked for writing by
-/// the calling thread.
-///
-/// **scope**:
-/// Whether the lock is stored in private or
-/// shared memory.
-#[inline]
-pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! {
- unsafe { cloudabi_sys_thread_exit(lock_, scope_) }
-}
-
-/// Temporarily yields execution of the calling thread.
-#[inline]
-pub unsafe fn thread_yield() -> errno {
- unsafe { cloudabi_sys_thread_yield() }
-}
+++ /dev/null
-#[allow(warnings)]
-mod cloudabi;
-pub use self::cloudabi::*;
+++ /dev/null
-pub use crate::sys::cloudabi::shims::args::*;
-
-#[allow(dead_code)]
-pub fn init(_: isize, _: *const *const u8) {}
-
-#[allow(dead_code)]
-pub fn cleanup() {}
+++ /dev/null
-use crate::mem;
-use crate::sync::atomic::{AtomicU32, Ordering};
-use crate::sys::cloudabi::abi;
-use crate::sys::mutex::{self, Mutex};
-use crate::sys::time::checked_dur2intervals;
-use crate::time::Duration;
-
-extern "C" {
- #[thread_local]
- static __pthread_thread_id: abi::tid;
-}
-
-pub struct Condvar {
- condvar: AtomicU32,
-}
-
-pub type MovableCondvar = Condvar;
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
-impl Condvar {
- pub const fn new() -> Condvar {
- Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) }
- }
-
- pub unsafe fn init(&mut self) {}
-
- pub unsafe fn notify_one(&self) {
- if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
- let ret = abi::condvar_signal(
- &self.condvar as *const AtomicU32 as *mut abi::condvar,
- abi::scope::PRIVATE,
- 1,
- );
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable");
- }
- }
-
- pub unsafe fn notify_all(&self) {
- if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
- let ret = abi::condvar_signal(
- &self.condvar as *const AtomicU32 as *mut abi::condvar,
- abi::scope::PRIVATE,
- abi::nthreads::MAX,
- );
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to broadcast on condition variable");
- }
- }
-
- pub unsafe fn wait(&self, mutex: &Mutex) {
- let mutex = mutex::raw(mutex);
- assert_eq!(
- mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- "This lock is not write-locked by this thread"
- );
-
- // Call into the kernel to wait on the condition variable.
- let subscription = abi::subscription {
- type_: abi::eventtype::CONDVAR,
- union: abi::subscription_union {
- condvar: abi::subscription_condvar {
- condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
- condvar_scope: abi::scope::PRIVATE,
- lock: mutex as *const AtomicU32 as *mut abi::lock,
- lock_scope: abi::scope::PRIVATE,
- },
- },
- ..mem::zeroed()
- };
- let mut event: mem::MaybeUninit<abi::event> = mem::MaybeUninit::uninit();
- let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit();
- let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr());
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to wait on condition variable");
- assert_eq!(
- event.assume_init().error,
- abi::errno::SUCCESS,
- "Failed to wait on condition variable"
- );
- }
-
- pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
- let mutex = mutex::raw(mutex);
- assert_eq!(
- mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- "This lock is not write-locked by this thread"
- );
-
- // Call into the kernel to wait on the condition variable.
- let timeout =
- checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds");
- let subscriptions = [
- abi::subscription {
- type_: abi::eventtype::CONDVAR,
- union: abi::subscription_union {
- condvar: abi::subscription_condvar {
- condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
- condvar_scope: abi::scope::PRIVATE,
- lock: mutex as *const AtomicU32 as *mut abi::lock,
- lock_scope: abi::scope::PRIVATE,
- },
- },
- ..mem::zeroed()
- },
- abi::subscription {
- type_: abi::eventtype::CLOCK,
- union: abi::subscription_union {
- clock: abi::subscription_clock {
- clock_id: abi::clockid::MONOTONIC,
- timeout,
- ..mem::zeroed()
- },
- },
- ..mem::zeroed()
- },
- ];
- let mut events: [mem::MaybeUninit<abi::event>; 2] = [mem::MaybeUninit::uninit(); 2];
- let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit();
- let ret = abi::poll(
- subscriptions.as_ptr(),
- mem::MaybeUninit::slice_as_mut_ptr(&mut events),
- 2,
- nevents.as_mut_ptr(),
- );
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to wait on condition variable");
- let nevents = nevents.assume_init();
- for i in 0..nevents {
- assert_eq!(
- events[i].assume_init().error,
- abi::errno::SUCCESS,
- "Failed to wait on condition variable"
- );
- if events[i].assume_init().type_ == abi::eventtype::CONDVAR {
- return true;
- }
- }
- false
- }
-
- pub unsafe fn destroy(&self) {
- assert_eq!(
- self.condvar.load(Ordering::Relaxed),
- abi::CONDVAR_HAS_NO_WAITERS.0,
- "Attempted to destroy a condition variable with blocked threads"
- );
- }
-}
+++ /dev/null
-use crate::mem;
-
-#[derive(Copy, Clone)]
-pub struct IoSlice<'a>(&'a [u8]);
-
-impl<'a> IoSlice<'a> {
- #[inline]
- pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
- IoSlice(buf)
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- self.0 = &self.0[n..]
- }
-
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- self.0
- }
-}
-
-pub struct IoSliceMut<'a>(&'a mut [u8]);
-
-impl<'a> IoSliceMut<'a> {
- #[inline]
- pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
- IoSliceMut(buf)
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- let slice = mem::replace(&mut self.0, &mut []);
- let (_, remaining) = slice.split_at_mut(n);
- self.0 = remaining;
- }
-
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- self.0
- }
-
- #[inline]
- pub fn as_mut_slice(&mut self) -> &mut [u8] {
- self.0
- }
-}
+++ /dev/null
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::io::ErrorKind;
-use crate::mem;
-
-#[path = "../unix/alloc.rs"]
-pub mod alloc;
-pub mod args;
-#[path = "../unix/cmath.rs"]
-pub mod cmath;
-pub mod condvar;
-pub mod io;
-#[path = "../unix/memchr.rs"]
-pub mod memchr;
-pub mod mutex;
-pub mod os;
-pub mod rwlock;
-pub mod stack_overflow;
-pub mod stdio;
-pub mod thread;
-#[path = "../unix/thread_local_key.rs"]
-pub mod thread_local_key;
-pub mod time;
-
-pub use crate::sys_common::os_str_bytes as os_str;
-
-mod abi;
-
-mod shims;
-pub use self::shims::*;
-
-#[allow(dead_code)]
-pub fn init() {}
-
-pub fn decode_error_kind(errno: i32) -> ErrorKind {
- match errno {
- x if x == abi::errno::ACCES as i32 => ErrorKind::PermissionDenied,
- x if x == abi::errno::ADDRINUSE as i32 => ErrorKind::AddrInUse,
- x if x == abi::errno::ADDRNOTAVAIL as i32 => ErrorKind::AddrNotAvailable,
- x if x == abi::errno::AGAIN as i32 => ErrorKind::WouldBlock,
- x if x == abi::errno::CONNABORTED as i32 => ErrorKind::ConnectionAborted,
- x if x == abi::errno::CONNREFUSED as i32 => ErrorKind::ConnectionRefused,
- x if x == abi::errno::CONNRESET as i32 => ErrorKind::ConnectionReset,
- x if x == abi::errno::EXIST as i32 => ErrorKind::AlreadyExists,
- x if x == abi::errno::INTR as i32 => ErrorKind::Interrupted,
- x if x == abi::errno::INVAL as i32 => ErrorKind::InvalidInput,
- x if x == abi::errno::NOENT as i32 => ErrorKind::NotFound,
- x if x == abi::errno::NOTCONN as i32 => ErrorKind::NotConnected,
- x if x == abi::errno::PERM as i32 => ErrorKind::PermissionDenied,
- x if x == abi::errno::PIPE as i32 => ErrorKind::BrokenPipe,
- x if x == abi::errno::TIMEDOUT as i32 => ErrorKind::TimedOut,
- _ => ErrorKind::Other,
- }
-}
-
-pub fn abort_internal() -> ! {
- core::intrinsics::abort();
-}
-
-pub use libc::strlen;
-
-pub fn hashmap_random_keys() -> (u64, u64) {
- unsafe {
- let mut v: mem::MaybeUninit<(u64, u64)> = mem::MaybeUninit::uninit();
- libc::arc4random_buf(v.as_mut_ptr() as *mut libc::c_void, mem::size_of_val(&v));
- v.assume_init()
- }
-}
-
-#[cfg_attr(feature = "backtrace", link(name = "unwind"))]
-#[link(name = "c")]
-#[link(name = "compiler_rt")]
-extern "C" {}
+++ /dev/null
-use crate::cell::Cell;
-use crate::mem;
-use crate::mem::MaybeUninit;
-use crate::sync::atomic::{AtomicU32, Ordering};
-use crate::sys::cloudabi::abi;
-use crate::sys::rwlock::{self, RWLock};
-
-extern "C" {
- #[thread_local]
- static __pthread_thread_id: abi::tid;
-}
-
-// Implement Mutex using an RWLock. This doesn't introduce any
-// performance overhead in this environment, as the operations would be
-// implemented identically.
-pub struct Mutex(RWLock);
-
-pub type MovableMutex = Mutex;
-
-pub unsafe fn raw(m: &Mutex) -> &AtomicU32 {
- rwlock::raw(&m.0)
-}
-
-impl Mutex {
- pub const fn new() -> Mutex {
- Mutex(RWLock::new())
- }
-
- pub unsafe fn init(&mut self) {
- // This function should normally reinitialize the mutex after
- // moving it to a different memory address. This implementation
- // does not require adjustments after moving.
- }
-
- pub unsafe fn try_lock(&self) -> bool {
- self.0.try_write()
- }
-
- pub unsafe fn lock(&self) {
- self.0.write()
- }
-
- pub unsafe fn unlock(&self) {
- self.0.write_unlock()
- }
-
- pub unsafe fn destroy(&self) {
- self.0.destroy()
- }
-}
-
-pub struct ReentrantMutex {
- lock: AtomicU32,
- recursion: Cell<u32>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), recursion: Cell::new(0) }
- }
-
- pub unsafe fn init(&self) {}
-
- pub unsafe fn try_lock(&self) -> bool {
- // Attempt to acquire the lock.
- if let Err(old) = self.lock.compare_exchange(
- abi::LOCK_UNLOCKED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- Ordering::Acquire,
- Ordering::Relaxed,
- ) {
- // If we fail to acquire the lock, it may be the case
- // that we've already acquired it and may need to recurse.
- if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 {
- self.recursion.set(self.recursion.get() + 1);
- true
- } else {
- false
- }
- } else {
- // Success.
- assert_eq!(self.recursion.get(), 0, "Mutex has invalid recursion count");
- true
- }
- }
-
- pub unsafe fn lock(&self) {
- if !self.try_lock() {
- // Call into the kernel to acquire a write lock.
- let lock = &self.lock as *const AtomicU32;
- let subscription = abi::subscription {
- type_: abi::eventtype::LOCK_WRLOCK,
- union: abi::subscription_union {
- lock: abi::subscription_lock {
- lock: lock as *mut abi::lock,
- lock_scope: abi::scope::PRIVATE,
- },
- },
- ..mem::zeroed()
- };
- let mut event = MaybeUninit::<abi::event>::uninit();
- let mut nevents = MaybeUninit::<usize>::uninit();
- // SAFE: The caller must to ensure that `event` and `nevents` are initialized.
- let ret =
- unsafe { abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()) };
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
- let event = event.assume_init();
- assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");
- }
- }
-
- pub unsafe fn unlock(&self) {
- assert_eq!(
- self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- "This mutex is locked by a different thread"
- );
-
- let r = self.recursion.get();
- if r > 0 {
- self.recursion.set(r - 1);
- } else if !self
- .lock
- .compare_exchange(
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- abi::LOCK_UNLOCKED.0,
- Ordering::Release,
- Ordering::Relaxed,
- )
- .is_ok()
- {
- // Lock is managed by kernelspace. Call into the kernel
- // to unblock waiting threads.
- let ret = abi::lock_unlock(
- &self.lock as *const AtomicU32 as *mut abi::lock,
- abi::scope::PRIVATE,
- );
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex");
- }
- }
-
- pub unsafe fn destroy(&self) {
- assert_eq!(
- self.lock.load(Ordering::Relaxed),
- abi::LOCK_UNLOCKED.0,
- "Attempted to destroy locked mutex"
- );
- assert_eq!(self.recursion.get(), 0, "Recursion counter invalid");
- }
-}
+++ /dev/null
-use crate::ffi::CStr;
-use crate::str;
-
-use libc::c_int;
-
-pub use crate::sys::cloudabi::shims::os::*;
-
-pub fn errno() -> i32 {
- extern "C" {
- #[thread_local]
- static errno: c_int;
- }
-
- unsafe { errno as i32 }
-}
-
-/// Gets a detailed string description for the given error number.
-pub fn error_string(errno: i32) -> String {
- // cloudlibc's strerror() is guaranteed to be thread-safe. There is
- // thus no need to use strerror_r().
- str::from_utf8(unsafe { CStr::from_ptr(libc::strerror(errno)) }.to_bytes()).unwrap().to_owned()
-}
-
-pub fn exit(code: i32) -> ! {
- unsafe { libc::exit(code as c_int) }
-}
+++ /dev/null
-use crate::mem;
-use crate::mem::MaybeUninit;
-use crate::sync::atomic::{AtomicU32, Ordering};
-use crate::sys::cloudabi::abi;
-
-extern "C" {
- #[thread_local]
- static __pthread_thread_id: abi::tid;
-}
-
-#[thread_local]
-static mut RDLOCKS_ACQUIRED: u32 = 0;
-
-pub struct RWLock {
- lock: AtomicU32,
-}
-
-pub unsafe fn raw(r: &RWLock) -> &AtomicU32 {
- &r.lock
-}
-
-unsafe impl Send for RWLock {}
-unsafe impl Sync for RWLock {}
-
-impl RWLock {
- pub const fn new() -> RWLock {
- RWLock { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0) }
- }
-
- pub unsafe fn try_read(&self) -> bool {
- let mut old = abi::LOCK_UNLOCKED.0;
- while let Err(cur) =
- self.lock.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
- {
- if (cur & abi::LOCK_WRLOCKED.0) != 0 {
- // Another thread already has a write lock.
- assert_ne!(
- old & !abi::LOCK_KERNEL_MANAGED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- "Attempted to acquire a read lock while holding a write lock"
- );
- return false;
- } else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 {
- // Lock has threads waiting for the lock. Only acquire
- // the lock if we have already acquired read locks. In
- // that case, it is justified to acquire this lock to
- // prevent a deadlock.
- return false;
- }
- old = cur;
- }
-
- RDLOCKS_ACQUIRED += 1;
- true
- }
-
- pub unsafe fn read(&self) {
- if !self.try_read() {
- // Call into the kernel to acquire a read lock.
- let subscription = abi::subscription {
- type_: abi::eventtype::LOCK_RDLOCK,
- union: abi::subscription_union {
- lock: abi::subscription_lock {
- lock: &self.lock as *const AtomicU32 as *mut abi::lock,
- lock_scope: abi::scope::PRIVATE,
- },
- },
- ..mem::zeroed()
- };
- let mut event = MaybeUninit::<abi::event>::uninit();
- let mut nevents = MaybeUninit::<usize>::uninit();
- let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr());
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock");
- let event = event.assume_init();
- assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire read lock");
-
- RDLOCKS_ACQUIRED += 1;
- }
- }
-
- pub unsafe fn read_unlock(&self) {
- // Perform a read unlock. We can do this in userspace, except when
- // other threads are blocked and we are performing the last unlock.
- // In that case, call into the kernel.
- //
- // Other threads may attempt to increment the read lock count,
- // meaning that the call into the kernel could be spurious. To
- // prevent this from happening, upgrade to a write lock first. This
- // allows us to call into the kernel, having the guarantee that the
- // lock value will not change in the meantime.
- assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count");
- let mut old = 1;
- loop {
- if old == 1 | abi::LOCK_KERNEL_MANAGED.0 {
- // Last read lock while threads are waiting. Attempt to upgrade
- // to a write lock before calling into the kernel to unlock.
- if let Err(cur) = self.lock.compare_exchange_weak(
- old,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0,
- Ordering::Acquire,
- Ordering::Relaxed,
- ) {
- old = cur;
- } else {
- // Call into the kernel to unlock.
- let ret = abi::lock_unlock(
- &self.lock as *const AtomicU32 as *mut abi::lock,
- abi::scope::PRIVATE,
- );
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
- break;
- }
- } else {
- // No threads waiting or not the last read lock. Just decrement
- // the read lock count.
- assert_ne!(old & !abi::LOCK_KERNEL_MANAGED.0, 0, "This rwlock is not locked");
- assert_eq!(
- old & abi::LOCK_WRLOCKED.0,
- 0,
- "Attempted to read-unlock a write-locked rwlock"
- );
- if let Err(cur) = self.lock.compare_exchange_weak(
- old,
- old - 1,
- Ordering::Acquire,
- Ordering::Relaxed,
- ) {
- old = cur;
- } else {
- break;
- }
- }
- }
-
- RDLOCKS_ACQUIRED -= 1;
- }
-
- pub unsafe fn try_write(&self) -> bool {
- // Attempt to acquire the lock.
- if let Err(old) = self.lock.compare_exchange(
- abi::LOCK_UNLOCKED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- Ordering::Acquire,
- Ordering::Relaxed,
- ) {
- // Failure. Crash upon recursive acquisition.
- assert_ne!(
- old & !abi::LOCK_KERNEL_MANAGED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- "Attempted to recursive write-lock a rwlock",
- );
- false
- } else {
- // Success.
- true
- }
- }
-
- pub unsafe fn write(&self) {
- if !self.try_write() {
- // Call into the kernel to acquire a write lock.
- let subscription = abi::subscription {
- type_: abi::eventtype::LOCK_WRLOCK,
- union: abi::subscription_union {
- lock: abi::subscription_lock {
- lock: &self.lock as *const AtomicU32 as *mut abi::lock,
- lock_scope: abi::scope::PRIVATE,
- },
- },
- ..mem::zeroed()
- };
- let mut event = MaybeUninit::<abi::event>::uninit();
- let mut nevents = MaybeUninit::<usize>::uninit();
- let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr());
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock");
- let event = event.assume_init();
- assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire write lock");
- }
- }
-
- pub unsafe fn write_unlock(&self) {
- assert_eq!(
- self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- "This rwlock is not write-locked by this thread"
- );
-
- if !self
- .lock
- .compare_exchange(
- __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
- abi::LOCK_UNLOCKED.0,
- Ordering::Release,
- Ordering::Relaxed,
- )
- .is_ok()
- {
- // Lock is managed by kernelspace. Call into the kernel
- // to unblock waiting threads.
- let ret = abi::lock_unlock(
- &self.lock as *const AtomicU32 as *mut abi::lock,
- abi::scope::PRIVATE,
- );
- assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
- }
- }
-
- pub unsafe fn destroy(&self) {
- assert_eq!(
- self.lock.load(Ordering::Relaxed),
- abi::LOCK_UNLOCKED.0,
- "Attempted to destroy locked rwlock"
- );
- }
-}
+++ /dev/null
-use crate::ffi::OsString;
-
-pub struct Args(());
-
-impl Args {
- pub fn inner_debug(&self) -> &[OsString] {
- &[]
- }
-}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> {
- None
- }
- fn size_hint(&self) -> (usize, Option<usize>) {
- (0, Some(0))
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize {
- 0
- }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- None
- }
-}
-
-pub fn args() -> Args {
- Args(())
-}
+++ /dev/null
-pub mod os {
- pub const FAMILY: &str = "cloudabi";
- pub const OS: &str = "cloudabi";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
+++ /dev/null
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::hash::{Hash, Hasher};
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
-use crate::path::{Path, PathBuf};
-use crate::sys::time::SystemTime;
-use crate::sys::{unsupported, Void};
-
-pub struct File(Void);
-
-pub struct FileAttr(Void);
-
-pub struct ReadDir(Void);
-
-pub struct DirEntry(Void);
-
-#[derive(Clone, Debug)]
-pub struct OpenOptions {}
-
-pub struct FilePermissions(Void);
-
-pub struct FileType(Void);
-
-#[derive(Debug)]
-pub struct DirBuilder {}
-
-impl FileAttr {
- pub fn size(&self) -> u64 {
- match self.0 {}
- }
-
- pub fn perm(&self) -> FilePermissions {
- match self.0 {}
- }
-
- pub fn file_type(&self) -> FileType {
- match self.0 {}
- }
-
- pub fn modified(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-
- pub fn accessed(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-
- pub fn created(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-}
-
-impl Clone for FileAttr {
- fn clone(&self) -> FileAttr {
- match self.0 {}
- }
-}
-
-impl FilePermissions {
- pub fn readonly(&self) -> bool {
- match self.0 {}
- }
-
- pub fn set_readonly(&mut self, _readonly: bool) {
- match self.0 {}
- }
-}
-
-impl Clone for FilePermissions {
- fn clone(&self) -> FilePermissions {
- match self.0 {}
- }
-}
-
-impl PartialEq for FilePermissions {
- fn eq(&self, _other: &FilePermissions) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for FilePermissions {}
-
-impl fmt::Debug for FilePermissions {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl FileType {
- pub fn is_dir(&self) -> bool {
- match self.0 {}
- }
-
- pub fn is_file(&self) -> bool {
- match self.0 {}
- }
-
- pub fn is_symlink(&self) -> bool {
- match self.0 {}
- }
-}
-
-impl Clone for FileType {
- fn clone(&self) -> FileType {
- match self.0 {}
- }
-}
-
-impl Copy for FileType {}
-
-impl PartialEq for FileType {
- fn eq(&self, _other: &FileType) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for FileType {}
-
-impl Hash for FileType {
- fn hash<H: Hasher>(&self, _h: &mut H) {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for FileType {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for ReadDir {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl Iterator for ReadDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- match self.0 {}
- }
-}
-
-impl DirEntry {
- pub fn path(&self) -> PathBuf {
- match self.0 {}
- }
-
- pub fn file_name(&self) -> OsString {
- match self.0 {}
- }
-
- pub fn metadata(&self) -> io::Result<FileAttr> {
- match self.0 {}
- }
-
- pub fn file_type(&self) -> io::Result<FileType> {
- match self.0 {}
- }
-}
-
-impl OpenOptions {
- pub fn new() -> OpenOptions {
- OpenOptions {}
- }
-
- pub fn read(&mut self, _read: bool) {}
- pub fn write(&mut self, _write: bool) {}
- pub fn append(&mut self, _append: bool) {}
- pub fn truncate(&mut self, _truncate: bool) {}
- pub fn create(&mut self, _create: bool) {}
- pub fn create_new(&mut self, _create_new: bool) {}
-}
-
-impl File {
- pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
- unsupported()
- }
-
- pub fn file_attr(&self) -> io::Result<FileAttr> {
- match self.0 {}
- }
-
- pub fn fsync(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn datasync(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn truncate(&self, _size: u64) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn flush(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
- match self.0 {}
- }
-
- pub fn duplicate(&self) -> io::Result<File> {
- match self.0 {}
- }
-
- pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-impl DirBuilder {
- pub fn new() -> DirBuilder {
- DirBuilder {}
- }
-
- pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
- unsupported()
- }
-}
-
-impl fmt::Debug for File {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
- unsupported()
-}
-
-pub fn unlink(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
- match perm.0 {}
-}
-
-pub fn rmdir(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
- unsupported()
-}
+++ /dev/null
-use crate::io;
-
-pub mod args;
-pub mod env;
-pub mod fs;
-pub mod net;
-pub mod os;
-#[path = "../../unix/path.rs"]
-pub mod path;
-pub mod pipe;
-pub mod process;
-
-// This enum is used as the storage for a bunch of types which can't actually exist.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub enum Void {}
-
-pub fn unsupported<T>() -> io::Result<T> {
- Err(io::Error::new(io::ErrorKind::Other, "This function is not available on CloudABI."))
-}
+++ /dev/null
-use crate::convert::TryFrom;
-use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::sys::{unsupported, Void};
-use crate::time::Duration;
-
-#[allow(unused_extern_crates)]
-pub extern crate libc as netc;
-
-pub struct TcpStream(Void);
-
-impl TcpStream {
- pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
- unsupported()
- }
-
- pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
- unsupported()
- }
-
- pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
- match self.0 {}
- }
-
- pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
- match self.0 {}
- }
-
- pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- match self.0 {}
- }
-
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- match self.0 {}
- }
-
- pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn duplicate(&self) -> io::Result<TcpStream> {
- match self.0 {}
- }
-
- pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn nodelay(&self) -> io::Result<bool> {
- match self.0 {}
- }
-
- pub fn set_ttl(&self, _: u32) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn ttl(&self) -> io::Result<u32> {
- match self.0 {}
- }
-
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- match self.0 {}
- }
-
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for TcpStream {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-pub struct TcpListener(Void);
-
-impl TcpListener {
- pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
- unsupported()
- }
-
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- match self.0 {}
- }
-
- pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
- match self.0 {}
- }
-
- pub fn duplicate(&self) -> io::Result<TcpListener> {
- match self.0 {}
- }
-
- pub fn set_ttl(&self, _: u32) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn ttl(&self) -> io::Result<u32> {
- match self.0 {}
- }
-
- pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn only_v6(&self) -> io::Result<bool> {
- match self.0 {}
- }
-
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- match self.0 {}
- }
-
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for TcpListener {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-pub struct UdpSocket(Void);
-
-impl UdpSocket {
- pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
- unsupported()
- }
-
- pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- match self.0 {}
- }
-
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- match self.0 {}
- }
-
- pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- match self.0 {}
- }
-
- pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- match self.0 {}
- }
-
- pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn duplicate(&self) -> io::Result<UdpSocket> {
- match self.0 {}
- }
-
- pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
- match self.0 {}
- }
-
- pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
- match self.0 {}
- }
-
- pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn broadcast(&self) -> io::Result<bool> {
- match self.0 {}
- }
-
- pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn multicast_loop_v4(&self) -> io::Result<bool> {
- match self.0 {}
- }
-
- pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
- match self.0 {}
- }
-
- pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn multicast_loop_v6(&self) -> io::Result<bool> {
- match self.0 {}
- }
-
- pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn set_ttl(&self, _: u32) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn ttl(&self) -> io::Result<u32> {
- match self.0 {}
- }
-
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- match self.0 {}
- }
-
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn send(&self, _: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for UdpSocket {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-pub struct LookupHost(Void);
-
-impl LookupHost {
- pub fn port(&self) -> u16 {
- match self.0 {}
- }
-}
-
-impl Iterator for LookupHost {
- type Item = SocketAddr;
- fn next(&mut self) -> Option<SocketAddr> {
- match self.0 {}
- }
-}
-
-impl TryFrom<&str> for LookupHost {
- type Error = io::Error;
-
- fn try_from(_v: &str) -> io::Result<LookupHost> {
- unsupported()
- }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
- type Error = io::Error;
-
- fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
- unsupported()
- }
-}
+++ /dev/null
-use crate::error::Error as StdError;
-use crate::ffi::{OsStr, OsString};
-use crate::fmt;
-use crate::io;
-use crate::iter;
-use crate::path::{self, PathBuf};
-use crate::sys::{unsupported, Void};
-
-pub fn getcwd() -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn chdir(_: &path::Path) -> io::Result<()> {
- unsupported()
-}
-
-pub type Env = iter::Empty<(OsString, OsString)>;
-
-pub fn env() -> Env {
- iter::empty()
-}
-
-pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
- Ok(None)
-}
-
-pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
- unsupported()
-}
-
-pub fn unsetenv(_: &OsStr) -> io::Result<()> {
- unsupported()
-}
-
-pub struct SplitPaths<'a>(&'a Void);
-
-pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
- panic!("unsupported")
-}
-
-impl<'a> Iterator for SplitPaths<'a> {
- type Item = PathBuf;
- fn next(&mut self) -> Option<PathBuf> {
- match *self.0 {}
- }
-}
-
-#[derive(Debug)]
-pub struct JoinPathsError;
-
-pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
-where
- I: Iterator<Item = T>,
- T: AsRef<OsStr>,
-{
- Err(JoinPathsError)
-}
-
-impl fmt::Display for JoinPathsError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- "not supported on CloudABI yet".fmt(f)
- }
-}
-
-impl StdError for JoinPathsError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "not supported on CloudABI yet"
- }
-}
-
-pub fn home_dir() -> Option<PathBuf> {
- None
-}
-
-pub fn temp_dir() -> PathBuf {
- PathBuf::from("/tmp")
-}
-
-pub fn current_exe() -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn getpid() -> u32 {
- 1
-}
+++ /dev/null
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
- match p1.0 {}
-}
+++ /dev/null
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
- env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
- pub stdin: Option<AnonPipe>,
- pub stdout: Option<AnonPipe>,
- pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
- Inherit,
- Null,
- MakePipe,
-}
-
-impl Command {
- pub fn new(_program: &OsStr) -> Command {
- Command { env: Default::default() }
- }
-
- pub fn arg(&mut self, _arg: &OsStr) {}
-
- pub fn env_mut(&mut self) -> &mut CommandEnv {
- &mut self.env
- }
-
- pub fn cwd(&mut self, _dir: &OsStr) {}
-
- pub fn stdin(&mut self, _stdin: Stdio) {}
-
- pub fn stdout(&mut self, _stdout: Stdio) {}
-
- pub fn stderr(&mut self, _stderr: Stdio) {}
-
- pub fn spawn(
- &mut self,
- _default: Stdio,
- _needs_stdin: bool,
- ) -> io::Result<(Process, StdioPipes)> {
- unsupported()
- }
-}
-
-impl From<AnonPipe> for Stdio {
- fn from(pipe: AnonPipe) -> Stdio {
- pipe.diverge()
- }
-}
-
-impl From<File> for Stdio {
- fn from(file: File) -> Stdio {
- file.diverge()
- }
-}
-
-impl fmt::Debug for Command {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
- }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
- pub fn success(&self) -> bool {
- match self.0 {}
- }
-
- pub fn code(&self) -> Option<i32> {
- match self.0 {}
- }
-}
-
-impl Clone for ExitStatus {
- fn clone(&self) -> ExitStatus {
- match self.0 {}
- }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
- fn eq(&self, _other: &ExitStatus) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Display for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
- pub const SUCCESS: ExitCode = ExitCode(false);
- pub const FAILURE: ExitCode = ExitCode(true);
-
- pub fn as_i32(&self) -> i32 {
- self.0 as i32
- }
-}
-
-pub struct Process(Void);
-
-impl Process {
- pub fn id(&self) -> u32 {
- match self.0 {}
- }
-
- pub fn kill(&mut self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn wait(&mut self) -> io::Result<ExitStatus> {
- match self.0 {}
- }
-
- pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
- match self.0 {}
- }
-}
+++ /dev/null
-#![cfg_attr(test, allow(dead_code))]
-
-pub unsafe fn init() {}
-
-pub unsafe fn cleanup() {}
+++ /dev/null
-use crate::io;
-use crate::sys::cloudabi::abi;
-
-pub struct Stdin(());
-pub struct Stdout(());
-pub struct Stderr(());
-
-impl Stdin {
- pub const fn new() -> Stdin {
- Stdin(())
- }
-}
-
-impl io::Read for Stdin {
- fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
- Ok(0)
- }
-}
-
-impl Stdout {
- pub const fn new() -> Stdout {
- Stdout(())
- }
-}
-
-impl io::Write for Stdout {
- fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
- Err(io::Error::new(
- io::ErrorKind::BrokenPipe,
- "Stdout is not connected to any output in this environment",
- ))
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-impl Stderr {
- pub const fn new() -> Stderr {
- Stderr(())
- }
-}
-
-impl io::Write for Stderr {
- fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
- Err(io::Error::new(
- io::ErrorKind::BrokenPipe,
- "Stderr is not connected to any output in this environment",
- ))
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-pub fn is_ebadf(err: &io::Error) -> bool {
- err.raw_os_error() == Some(abi::errno::BADF as i32)
-}
-
-pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
-
-pub fn panic_output() -> Option<impl io::Write> {
- Some(Stderr::new())
-}
+++ /dev/null
-use crate::cmp;
-use crate::ffi::CStr;
-use crate::io;
-use crate::mem;
-use crate::ptr;
-use crate::sys::cloudabi::abi;
-use crate::sys::time::checked_dur2intervals;
-use crate::time::Duration;
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
-
-pub struct Thread {
- id: libc::pthread_t,
-}
-
-// CloudABI has pthread_t as a pointer in which case we still want
-// a thread to be Send/Sync
-unsafe impl Send for Thread {}
-unsafe impl Sync for Thread {}
-
-impl Thread {
- // unsafe: see thread::Builder::spawn_unchecked for safety requirements
- pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
- let p = Box::into_raw(box p);
- let mut native: libc::pthread_t = mem::zeroed();
- let mut attr: libc::pthread_attr_t = mem::zeroed();
- assert_eq!(libc::pthread_attr_init(&mut attr), 0);
-
- let stack_size = cmp::max(stack, min_stack_size(&attr));
- assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
-
- let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
- // Note: if the thread creation fails and this assert fails, then p will
- // be leaked. However, an alternative design could cause double-free
- // which is clearly worse.
- assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
-
- return if ret != 0 {
- // The thread failed to start and as a result p was not consumed. Therefore, it is
- // safe to reconstruct the box so that it gets deallocated.
- drop(Box::from_raw(p));
- Err(io::Error::from_raw_os_error(ret))
- } else {
- Ok(Thread { id: native })
- };
-
- extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
- unsafe {
- // Let's run some code.
- Box::from_raw(main as *mut Box<dyn FnOnce()>)();
- }
- ptr::null_mut()
- }
- }
-
- pub fn yield_now() {
- let ret = unsafe { abi::thread_yield() };
- debug_assert_eq!(ret, abi::errno::SUCCESS);
- }
-
- pub fn set_name(_name: &CStr) {
- // CloudABI has no way to set a thread name.
- }
-
- pub fn sleep(dur: Duration) {
- let timeout =
- checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds");
- unsafe {
- let subscription = abi::subscription {
- type_: abi::eventtype::CLOCK,
- union: abi::subscription_union {
- clock: abi::subscription_clock {
- clock_id: abi::clockid::MONOTONIC,
- timeout,
- ..mem::zeroed()
- },
- },
- ..mem::zeroed()
- };
- let mut event = mem::MaybeUninit::<abi::event>::uninit();
- let mut nevents = mem::MaybeUninit::<usize>::uninit();
- let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr());
- assert_eq!(ret, abi::errno::SUCCESS);
- let event = event.assume_init();
- assert_eq!(event.error, abi::errno::SUCCESS);
- }
- }
-
- pub fn join(self) {
- unsafe {
- let ret = libc::pthread_join(self.id, ptr::null_mut());
- mem::forget(self);
- assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
- }
- }
-}
-
-impl Drop for Thread {
- fn drop(&mut self) {
- let ret = unsafe { libc::pthread_detach(self.id) };
- debug_assert_eq!(ret, 0);
- }
-}
-
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
- pub type Guard = !;
- pub unsafe fn current() -> Option<Guard> {
- None
- }
- pub unsafe fn init() -> Option<Guard> {
- None
- }
-}
-
-fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
- libc::PTHREAD_STACK_MIN
-}
+++ /dev/null
-use crate::mem;
-use crate::sys::cloudabi::abi;
-use crate::time::Duration;
-
-const NSEC_PER_SEC: abi::timestamp = 1_000_000_000;
-
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant {
- t: abi::timestamp,
-}
-
-pub fn checked_dur2intervals(dur: &Duration) -> Option<abi::timestamp> {
- dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as abi::timestamp)
-}
-
-impl Instant {
- pub fn now() -> Instant {
- unsafe {
- let mut t: mem::MaybeUninit<abi::timestamp> = mem::MaybeUninit::uninit();
- let ret = abi::clock_time_get(abi::clockid::MONOTONIC, 0, t.as_mut_ptr());
- assert_eq!(ret, abi::errno::SUCCESS);
- Instant { t: t.assume_init() }
- }
- }
-
- pub fn actually_monotonic() -> bool {
- true
- }
-
- pub const fn zero() -> Instant {
- Instant { t: 0 }
- }
-
- pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
- let diff = self.t.checked_sub(other.t)?;
- Some(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32))
- }
-
- pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
- Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
- }
-
- pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
- Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
- }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct SystemTime {
- t: abi::timestamp,
-}
-
-impl SystemTime {
- pub fn now() -> SystemTime {
- unsafe {
- let mut t: mem::MaybeUninit<abi::timestamp> = mem::MaybeUninit::uninit();
- let ret = abi::clock_time_get(abi::clockid::REALTIME, 0, t.as_mut_ptr());
- assert_eq!(ret, abi::errno::SUCCESS);
- SystemTime { t: t.assume_init() }
- }
- }
-
- pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
- if self.t >= other.t {
- let diff = self.t - other.t;
- Ok(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32))
- } else {
- let diff = other.t - self.t;
- Err(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32))
- }
- }
-
- pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_add(checked_dur2intervals(other)?)? })
- }
-
- pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
- }
-}
-
-pub const UNIX_EPOCH: SystemTime = SystemTime { t: 0 };
unsupported()
}
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
unsupported()
}
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
unsupported()
}
} else if #[cfg(windows)] {
mod windows;
pub use self::windows::*;
- } else if #[cfg(target_os = "cloudabi")] {
- mod cloudabi;
- pub use self::cloudabi::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use self::hermit::*;
// On unix we'll document what's already available
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as unix_ext;
- } else if #[cfg(any(target_os = "cloudabi",
- target_os = "hermit",
+ } else if #[cfg(any(target_os = "hermit",
target_arch = "wasm32",
all(target_vendor = "fortanix", target_env = "sgx")))] {
- // On CloudABI and wasm right now the module below doesn't compile
+ // On wasm right now the module below doesn't compile
// (missing things in `libc` which is empty) so just omit everything
// with an empty module
#[unstable(issue = "none", feature = "std_internals")]
#[allow(missing_docs)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as windows_ext;
- } else if #[cfg(any(target_os = "cloudabi",
- target_os = "hermit",
+ } else if #[cfg(any(target_os = "hermit",
target_arch = "wasm32",
all(target_vendor = "fortanix", target_env = "sgx")))] {
- // On CloudABI and wasm right now the shim below doesn't compile, so
+ // On wasm right now the shim below doesn't compile, so
// just omit it
#[unstable(issue = "none", feature = "std_internals")]
#[allow(missing_docs)]
/// descriptor.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub trait FromRawFd {
+ /// An associated type that contains relevant metadata for `Self`.
+ type Metadata: Default;
+
/// Constructs a new instance of `Self` from the given raw file
- /// descriptor.
+ /// descriptor and metadata.
///
/// This function **consumes ownership** of the specified file
/// descriptor. The returned object will take responsibility for closing
/// accidentally allow violating this contract which can cause memory
/// unsafety in code that relies on it being true.
#[unstable(feature = "sgx_platform", issue = "56975")]
- unsafe fn from_raw_fd(fd: RawFd) -> Self;
+ unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self;
}
/// A trait to express the ability to consume an object and acquire ownership of
}
}
+/// Metadata for `TcpStream`.
+#[derive(Debug, Clone, Default)]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct TcpStreamMetadata {
+ /// Local address of the TCP stream
+ pub local_addr: Option<String>,
+ /// Peer address of the TCP stream
+ pub peer_addr: Option<String>,
+}
+
impl FromRawFd for net::TcpStream {
- unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ type Metadata = TcpStreamMetadata;
+
+ unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream {
let fd = sys::fd::FileDesc::from_inner(fd);
- let socket = sys::net::Socket::from_inner(fd);
- net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, None)))
+ let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
+ net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, metadata.peer_addr)))
}
}
+/// Metadata for `TcpListener`.
+#[derive(Debug, Clone, Default)]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct TcpListenerMetadata {
+ /// Local address of the TCP listener
+ pub local_addr: Option<String>,
+}
+
impl FromRawFd for net::TcpListener {
- unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ type Metadata = TcpListenerMetadata;
+
+ unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener {
let fd = sys::fd::FileDesc::from_inner(fd);
- let socket = sys::net::Socket::from_inner(fd);
+ let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket))
}
}
}
}
-impl FromInner<FileDesc> for Socket {
- fn from_inner(inner: FileDesc) -> Socket {
- Socket { inner: Arc::new(inner), local_addr: None }
+impl FromInner<(FileDesc, Option<String>)> for Socket {
+ fn from_inner((inner, local_addr): (FileDesc, Option<String>)) -> Socket {
+ Socket { inner: Arc::new(inner), local_addr }
}
}
/// Creates a new symbolic link on the filesystem.
///
-/// The `dst` path will be a symbolic link pointing to the `src` path.
+/// The `link` path will be a symbolic link pointing to the `original` path.
///
/// # Examples
///
/// }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- sys::fs::symlink(src.as_ref(), dst.as_ref())
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink(original.as_ref(), link.as_ref())
}
/// Unix-specific extensions to [`fs::DirBuilder`].
}
}
-pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
- let src = cstr(src)?;
- let dst = cstr(dst)?;
- cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?;
+pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
+ let original = cstr(original)?;
+ let link = cstr(link)?;
+ cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) })?;
Ok(())
}
-pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
- let src = cstr(src)?;
- let dst = cstr(dst)?;
+pub fn link(original: &Path, link: &Path) -> io::Result<()> {
+ let original = cstr(original)?;
+ let link = cstr(link)?;
cfg_if::cfg_if! {
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] {
// VxWorks, Redox, and old versions of Android lack `linkat`, so use
// `link` instead. POSIX leaves it implementation-defined whether
// `link` follows symlinks, so rely on the `symlink_hard_link` test
// in library/std/src/fs/tests.rs to check the behavior.
- cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
+ cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?;
} else {
// Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives
// us a flag to specify how symlinks should be handled. Pass 0 as
// the flags argument, meaning don't follow symlinks.
- cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?;
+ cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?;
}
}
Ok(())
} else {
syscall(
concat_idents!(SYS_, $name),
- $($arg_name as c_long),*
+ $($arg_name),*
) as $ret
}
}
unsupported()
}
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
unsupported()
}
}
}
-pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
- let (dst, dst_file) = open_parent(dst)?;
- dst.symlink(osstr2str(src.as_ref())?, osstr2str(dst_file.as_ref())?)
+pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
+ let (link, link_file) = open_parent(link)?;
+ link.symlink(osstr2str(original.as_ref())?, osstr2str(link_file.as_ref())?)
}
-pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
- let (src, src_file) = open_parent(src)?;
- let (dst, dst_file) = open_parent(dst)?;
- src.link(
+pub fn link(original: &Path, link: &Path) -> io::Result<()> {
+ let (original, original_file) = open_parent(original)?;
+ let (link, link_file) = open_parent(link)?;
+ original.link(
wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
- osstr2str(src_file.as_ref())?,
- &dst,
- osstr2str(dst_file.as_ref())?,
+ osstr2str(original_file.as_ref())?,
+ &link,
+ osstr2str(link_file.as_ref())?,
)
}
}
}
+ $(#[$meta])*
pub use $symbol::call as $symbol;
)*)
}
/// Creates a new file symbolic link on the filesystem.
///
-/// The `dst` path will be a file symbolic link pointing to the `src`
+/// The `link` path will be a file symbolic link pointing to the `original`
/// path.
///
/// # Examples
/// }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), false)
+pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
}
/// Creates a new directory symlink on the filesystem.
///
-/// The `dst` path will be a directory symbolic link pointing to the `src`
+/// The `link` path will be a directory symbolic link pointing to the `original`
/// path.
///
/// # Examples
/// }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), true)
+pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
}
file.readlink()
}
-pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
- symlink_inner(src, dst, false)
+pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
+ symlink_inner(original, link, false)
}
-pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> {
- let src = to_u16s(src)?;
- let dst = to_u16s(dst)?;
+pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> {
+ let original = to_u16s(original)?;
+ let link = to_u16s(link)?;
let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
// Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
// Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
// added to dwFlags to opt into this behaviour.
let result = cvt(unsafe {
c::CreateSymbolicLinkW(
- dst.as_ptr(),
- src.as_ptr(),
+ link.as_ptr(),
+ original.as_ptr(),
flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE,
) as c::BOOL
});
if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) {
// Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE,
// so if we encounter ERROR_INVALID_PARAMETER, retry without that flag.
- cvt(unsafe { c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL })?;
+ cvt(unsafe {
+ c::CreateSymbolicLinkW(link.as_ptr(), original.as_ptr(), flags) as c::BOOL
+ })?;
} else {
return Err(err);
}
}
#[cfg(not(target_vendor = "uwp"))]
-pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
- let src = to_u16s(src)?;
- let dst = to_u16s(dst)?;
- cvt(unsafe { c::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) })?;
+pub fn link(original: &Path, link: &Path) -> io::Result<()> {
+ let original = to_u16s(original)?;
+ let link = to_u16s(link)?;
+ cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?;
Ok(())
}
#[cfg(target_vendor = "uwp")]
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
return Err(io::Error::new(io::ErrorKind::Other, "hard link are not supported on UWP"));
}
}
#[allow(dead_code)]
-pub fn symlink_junction<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
- symlink_junction_inner(src.as_ref(), dst.as_ref())
+pub fn symlink_junction<P: AsRef<Path>, Q: AsRef<Path>>(
+ original: P,
+ junction: Q,
+) -> io::Result<()> {
+ symlink_junction_inner(original.as_ref(), junction.as_ref())
}
// Creating a directory junction on windows involves dealing with reparse
//
// http://www.flexhex.com/docs/articles/hard-links.phtml
#[allow(dead_code)]
-fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
+fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
let d = DirBuilder::new();
d.mkdir(&junction)?;
// FIXME: this conversion is very hacky
let v = br"\??\";
let v = v.iter().map(|x| *x as u16);
- for c in v.chain(target.as_os_str().encode_wide()) {
+ for c in v.chain(original.as_os_str().encode_wide()) {
*buf.offset(i) = c;
i += 1;
}
pub mod wtf8;
cfg_if::cfg_if! {
- if #[cfg(any(target_os = "cloudabi",
- target_os = "l4re",
+ if #[cfg(any(target_os = "l4re",
target_os = "hermit",
feature = "restricted-std",
all(target_arch = "wasm32", not(target_os = "emscripten")),
}
} else if #[cfg(any(
target_os = "android",
- target_os = "cloudabi",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "ios",
///
/// | Platform | System call |
/// |:---------:|:--------------------------------------------------------------------:|
-/// | CloudABI | [clock_time_get (Monotonic Clock)] |
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Monotonic Clock)] |
/// | Darwin | [mach_absolute_time] |
/// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#clock_time_get
/// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime
/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
-/// [clock_time_get (Monotonic Clock)]: https://nuxi.nl/cloudabi/#clock_time_get
///
/// **Disclaimer:** These system calls might change over time.
///
///
/// | Platform | System call |
/// |:---------:|:--------------------------------------------------------------------:|
-/// | CloudABI | [clock_time_get (Realtime Clock)] |
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Realtime Clock)] |
/// | Darwin | [gettimeofday] |
/// | WASI | [__wasi_clock_time_get (Realtime Clock)] |
/// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] |
///
-/// [clock_time_get (Realtime Clock)]: https://nuxi.nl/cloudabi/#clock_time_get
/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time
/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
/// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html
backtrace = ["std/backtrace"]
compiler-builtins-c = ["std/compiler-builtins-c"]
compiler-builtins-mem = ["std/compiler-builtins-mem"]
+compiler-builtins-asm = ["std/compiler-builtins-asm"]
+compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"]
llvm-libunwind = ["std/llvm-libunwind"]
system-llvm-libunwind = ["std/system-llvm-libunwind"]
panic-unwind = ["std/panic_unwind"]
#![crate_name = "test"]
#![unstable(feature = "test", issue = "50297")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
-#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))]
+#![cfg_attr(unix, feature(libc))]
#![feature(rustc_private)]
#![feature(nll)]
-#![feature(bool_to_option)]
#![feature(available_concurrency)]
#![feature(internal_output_capture)]
#![feature(panic_unwind)]
running_tests.remove(test);
}
timed_out
- };
+ }
fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
running_tests.values().min().map(|next_timeout| {
let now = Instant::now();
if *next_timeout >= now { *next_timeout - now } else { Duration::new(0, 0) }
})
- };
+ }
if concurrency == 1 {
while !remaining.is_empty() {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("redox") {
// redox is handled in lib.rs
- } else if target.contains("cloudabi") {
- println!("cargo:rustc-link-lib=unwind");
}
}
unix,
windows,
target_os = "psp",
- target_os = "cloudabi",
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
mod libunwind;
"src/tools/rust-analyzer",
"src/tools/rustfmt",
"src/tools/rust-installer",
-
- # We do not format this file as it is externally sourced and auto-generated.
- "library/std/src/sys/cloudabi/abi/cloudabi.rs",
]
#
# This works even in a repository that has not yet initialized
# submodules.
+ top_level = subprocess.check_output([
+ "git", "rev-parse", "--show-toplevel",
+ ]).decode(sys.getdefaultencoding()).strip()
llvm_sha = subprocess.check_output([
"git", "log", "--author=bors", "--format=%H", "-n1",
"-m", "--first-parent",
"--",
- "src/llvm-project",
- "src/bootstrap/download-ci-llvm-stamp",
+ "{}/src/llvm-project".format(top_level),
+ "{}/src/bootstrap/download-ci-llvm-stamp".format(top_level),
]).decode(sys.getdefaultencoding()).strip()
llvm_assertions = self.get_toml('assertions', 'llvm') == 'true'
if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
// misc
pub low_priority: bool,
pub channel: String,
+ pub description: Option<String>,
pub verbose_tests: bool,
pub save_toolstates: Option<PathBuf>,
pub print_step_timings: bool,
pub ranlib: Option<PathBuf>,
pub linker: Option<PathBuf>,
pub ndk: Option<PathBuf>,
- pub sanitizers: bool,
- pub profiler: bool,
+ pub sanitizers: Option<bool>,
+ pub profiler: Option<bool>,
pub crt_static: Option<bool>,
pub musl_root: Option<PathBuf>,
pub musl_libdir: Option<PathBuf>,
parallel_compiler: Option<bool>,
default_linker: Option<String>,
channel: Option<String>,
+ description: Option<String>,
musl_root: Option<String>,
rpath: Option<bool>,
verbose_tests: Option<bool>,
.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
set(&mut config.backtrace, rust.backtrace);
set(&mut config.channel, rust.channel);
+ config.description = rust.description;
set(&mut config.rust_dist_src, rust.dist_src);
set(&mut config.verbose_tests, rust.verbose_tests);
// in the case "false" is set explicitly, do not overwrite the command line args
target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
target.wasi_root = cfg.wasi_root.map(PathBuf::from);
target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
- target.sanitizers = cfg.sanitizers.unwrap_or(build.sanitizers.unwrap_or_default());
- target.profiler = cfg.profiler.unwrap_or(build.profiler.unwrap_or_default());
+ target.sanitizers = cfg.sanitizers;
+ target.profiler = cfg.profiler;
config.target_config.insert(TargetSelection::from_user(&triple), target);
}
}
pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
- self.target_config.get(&target).map(|t| t.sanitizers).unwrap_or(self.sanitizers)
+ self.target_config.get(&target).map(|t| t.sanitizers).flatten().unwrap_or(self.sanitizers)
}
pub fn any_sanitizers_enabled(&self) -> bool {
- self.target_config.values().any(|t| t.sanitizers) || self.sanitizers
+ self.target_config.values().any(|t| t.sanitizers == Some(true)) || self.sanitizers
}
pub fn profiler_enabled(&self, target: TargetSelection) -> bool {
- self.target_config.get(&target).map(|t| t.profiler).unwrap_or(self.profiler)
+ self.target_config.get(&target).map(|t| t.profiler).flatten().unwrap_or(self.profiler)
}
pub fn any_profiler_enabled(&self) -> bool {
- self.target_config.values().any(|t| t.profiler) || self.profiler
+ self.target_config.values().any(|t| t.profiler == Some(true)) || self.profiler
}
pub fn llvm_enabled(&self) -> bool {
v("experimental-targets", "llvm.experimental-targets",
"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")
# Used on systems where "cc" is unavailable
v("default-linker", "rust.default-linker", "the default linker")
/// Note that this is a descriptive string which includes the commit date,
/// sha, version, etc.
fn rust_version(&self) -> String {
- self.rust_info.version(self, &self.version)
+ let mut version = self.rust_info.version(self, &self.version);
+ if let Some(ref s) = self.config.description {
+ version.push_str(" (");
+ version.push_str(s);
+ version.push_str(")");
+ }
+ version
}
/// Returns the full commit hash.
let host = self.host;
let compiler = builder.compiler(0, host);
+ // We need `ToolStd` for the locally-built sysroot because
+ // compiletest uses unstable features of the `test` crate.
+ builder.ensure(compile::Std { compiler, target: host });
let cargo = tool::prepare_tool_cargo(
builder,
compiler,
- Mode::ToolBootstrap,
+ Mode::ToolStd,
host,
"test",
"src/tools/compiletest",
mkdir -p $SYSROOT
pushd $SYSROOT
-centos_base=http://vault.centos.org/altarch/7.3.1611/os/ppc64le/Packages/
-glibc_v=2.17-157.el7
-kernel_v=3.10.0-514.el7
+# centos_base=http://vault.centos.org/altarch/7.3.1611/os/ppc64le/Packages/
+# Mirrored from centos_base above
+centos_base=https://ci-mirrors.rust-lang.org/rustc
+glibc_v=2.17-157-2020-11-25.el7
+kernel_v=3.10.0-514-2020-11-25.el7
for package in glibc{,-devel,-headers}-$glibc_v kernel-headers-$kernel_v; do
curl $centos_base/$package.ppc64le.rpm | \
rpm2cpio - | cpio -idm
+++ /dev/null
-#!/bin/bash
-
-set -eux
-
-# Install prerequisites.
-apt-get update
-apt-get install -y --no-install-recommends \
- apt-transport-https \
- ca-certificates \
- clang-5.0 \
- cmake \
- curl \
- file \
- g++ \
- gdb \
- git \
- lld-5.0 \
- make \
- ninja-build \
- python \
- sudo \
- xz-utils
-
-# Set up a Clang-based cross compiler toolchain.
-# Based on the steps described at https://nuxi.nl/cloudabi/debian/
-target=$1
-for tool in ar nm objdump ranlib size; do
- ln -s ../lib/llvm-5.0/bin/llvm-${tool} /usr/bin/${target}-${tool}
-done
-ln -s ../lib/llvm-5.0/bin/clang /usr/bin/${target}-cc
-ln -s ../lib/llvm-5.0/bin/clang /usr/bin/${target}-c++
-ln -s ../lib/llvm-5.0/bin/lld /usr/bin/${target}-ld
-ln -s ../../${target} /usr/lib/llvm-5.0/${target}
-
-# Install the C++ runtime libraries from CloudABI Ports.
-apt-key adv --batch --yes --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0DA51B8531344B15
-add-apt-repository -y 'deb https://nuxi.nl/distfiles/cloudabi-ports/debian/ cloudabi cloudabi'
-
-apt-get update
-apt-get install -y "${target//_/-}-cxx-runtime"
- [Known Issues](targets/known-issues.md)
- [Profile-guided Optimization](profile-guided-optimization.md)
- [Linker-plugin based LTO](linker-plugin-lto.md)
+- [Exploit Mitigations](exploit-mitigations.md)
- [Contributing to `rustc`](contributing.md)
--- /dev/null
+# Exploit Mitigations
+
+This chapter documents the exploit mitigations supported by the Rust
+compiler, and is by no means an extensive survey of the Rust programming
+language’s security features.
+
+This chapter is for software engineers working with the Rust programming
+language, and assumes prior knowledge of the Rust programming language and
+its toolchain.
+
+
+## Introduction
+
+The Rust programming language provides memory[1] and thread[2] safety
+guarantees via its ownership[3], references and borrowing[4], and slice
+types[5] features. However, Unsafe Rust[6] introduces unsafe blocks, unsafe
+functions and methods, unsafe traits, and new types that are not subject to
+the borrowing rules.
+
+Parts of the Rust standard library are implemented as safe abstractions over
+unsafe code (and historically have been vulnerable to memory corruption[7]).
+Furthermore, the Rust code and documentation encourage creating safe
+abstractions over unsafe code. This can cause a false sense of security if
+unsafe code is not properly reviewed and tested.
+
+Unsafe Rust introduces features that do not provide the same memory and
+thread safety guarantees. This causes programs or libraries to be
+susceptible to memory corruption (CWE-119)[8] and concurrency issues
+(CWE-557)[9]. Modern C and C++ compilers provide exploit mitigations to
+increase the difficulty to exploit vulnerabilities resulting from these
+issues. Therefore, the Rust compiler must also support these exploit
+mitigations in order to mitigate vulnerabilities resulting from the use of
+Unsafe Rust. This chapter documents these exploit mitigations and how they
+apply to Rust.
+
+This chapter does not discuss the effectiveness of these exploit mitigations
+as they vary greatly depending on several factors besides their design and
+implementation, but rather describe what they do, so their effectiveness can
+be understood within a given context.
+
+
+## Exploit mitigations
+
+This section documents the exploit mitigations applicable to the Rust
+compiler when building programs for the Linux operating system on the AMD64
+architecture and equivalent.<sup id="fnref:1" role="doc-noteref"><a
+href="#fn:1" class="footnote">1</a></sup>
+
+The Rust Programming Language currently has no specification. The Rust
+compiler (i.e., rustc) is the language reference implementation. All
+references to “the Rust compiler” in this chapter refer to the language
+reference implementation.
+
+Table I \
+Summary of exploit mitigations supported by the Rust compiler when building
+programs for the Linux operating system on the AMD64 architecture and
+equivalent.
+<table class="table">
+ <tr>
+ <td><strong>Exploit mitigation</strong>
+ </td>
+ <td><strong>Supported and enabled by default</strong>
+ </td>
+ <td><strong>Since</strong>
+ </td>
+ </tr>
+ <tr>
+ <td>Position-independent executable
+ </td>
+ <td>Yes
+ </td>
+ <td>0.12.0 (2014-10-09)
+ </td>
+ </tr>
+ <tr>
+ <td>Integer overflow checks
+ </td>
+ <td>Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled)
+ </td>
+ <td>1.1.0 (2015-06-25)
+ </td>
+ </tr>
+ <tr>
+ <td>Non-executable memory regions
+ </td>
+ <td>Yes
+ </td>
+ <td>1.8.0 (2016-04-14)
+ </td>
+ </tr>
+ <tr>
+ <td>Stack clashing protection
+ </td>
+ <td>Yes
+ </td>
+ <td>1.20.0 (2017-08-31)
+ </td>
+ </tr>
+ <tr>
+ <td>Read-only relocations and immediate binding
+ </td>
+ <td>Yes
+ </td>
+ <td>1.21.0 (2017-10-12)
+ </td>
+ </tr>
+ <tr>
+ <td>Heap corruption protection
+ </td>
+ <td>Yes
+ </td>
+ <td>1.32.0 (2019-01-17) (via operating system default or specified allocator)
+ </td>
+ </tr>
+ <tr>
+ <td>Stack smashing protection
+ </td>
+ <td>No
+ </td>
+ <td>
+ </td>
+ </tr>
+ <tr>
+ <td>Forward-edge control flow protection
+ </td>
+ <td>No
+ </td>
+ <td>
+ </td>
+ </tr>
+ <tr>
+ <td>Backward-edge control flow protection (e.g., shadow and safe stack)
+ </td>
+ <td>No
+ </td>
+ <td>
+ </td>
+ </tr>
+</table>
+
+<small id="fn:1">1\. See
+<https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
+for a list of targets and their default options. <a href="#fnref:1"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Position-independent executable
+
+Position-independent executable increases the difficulty of the use of code
+reuse exploitation techniques, such as return-oriented programming (ROP) and
+variants, by generating position-independent code for the executable, and
+instructing the dynamic linker to load it similarly to a shared object at a
+random load address, thus also benefiting from address-space layout
+randomization (ASLR). This is also referred to as “full ASLR”.
+
+The Rust compiler supports position-independent executable, and enables it
+by default since version 0.12.0 (2014-10-09)[10]–[13].
+
+```text
+$ readelf -h target/release/hello-rust | grep Type:
+ Type: DYN (Shared object file)
+```
+Fig. 1. Checking if an executable is a position-independent executable.
+
+An executable with an object type of `ET_DYN` (i.e., shared object) and not
+`ET_EXEC` (i.e., executable) is a position-independent executable (see Fig.
+1).
+
+
+### Integer overflow checks
+
+Integer overflow checks protects programs from undefined and unintended
+behavior (which may cause vulnerabilities) by checking for results of signed
+and unsigned integer computations that cannot be represented in their type,
+resulting in an overflow or wraparound.
+
+The Rust compiler supports integer overflow checks, and enables it when
+debug assertions are enabled since version 1.1.0 (2015-06-25)[14]–[20].
+
+```compile_fail
+fn main() {
+ let u: u8 = 255;
+ println!("u: {}", u + 1);
+}
+```
+Fig. 2. hello-rust-integer program.
+
+```text
+$ cargo run
+ Compiling hello-rust-integer v0.1.0 (/home/rcvalle/hello-rust-integer)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.23s
+ Running `target/debug/hello-rust-integer`
+thread 'main' panicked at 'attempt to add with overflow', src/main.rs:3:23
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
+```
+Fig. 3. Build and execution of hello-rust-integer with debug assertions
+enabled.
+
+```text
+$ cargo run --release
+ Compiling hello-rust-integer v0.1.0 (/home/rcvalle/hello-rust-integer)
+ Finished release [optimized] target(s) in 0.23s
+ Running `target/release/hello-rust-integer`
+u: 0
+```
+Fig. 4. Build and execution of hello-rust-integer with debug assertions
+disabled.
+
+Integer overflow checks are enabled when debug assertions are enabled (see
+Fig. 3), and disabled when debug assertions are disabled (see Fig. 4). To
+enable integer overflow checks independently, use the option to control
+integer overflow checks, scoped attributes, or explicit checking methods
+such as `checked_add`<sup id="fnref:2" role="doc-noteref"><a href="#fn:2"
+class="footnote">2</a></sup>.
+
+It is recommended that explicit wrapping methods such as `wrapping_add` be
+used when wrapping semantics are intended, and that explicit checking and
+wrapping methods always be used when using Unsafe Rust.
+
+<small id="fn:2">2\. See <https://doc.rust-lang.org/std/primitive.u32.html>
+for more information on the checked, overflowing, saturating, and wrapping
+methods (using u32 as an example). <a href="#fnref:2"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Non-executable memory regions
+
+Non-executable memory regions increase the difficulty of exploitation by
+limiting the memory regions that can be used to execute arbitrary code. Most
+modern processors provide support for the operating system to mark memory
+regions as non executable, but it was previously emulated by software, such
+as in grsecurity/PaX's
+[PAGEEXEC](https://pax.grsecurity.net/docs/pageexec.txt) and
+[SEGMEXEC](https://pax.grsecurity.net/docs/segmexec.txt), on processors that
+did not provide support for it. This is also known as “No Execute (NX) Bit”,
+“Execute Disable (XD) Bit”, “Execute Never (XN) Bit”, and others.
+
+The Rust compiler supports non-executable memory regions, and enables it by
+default since its initial release, version 0.1 (2012-01-20)[21], [22], but
+has regressed since then[23]–[25], and enforced by default since version
+1.8.0 (2016-04-14)[25].
+
+```text
+$ readelf -l target/release/hello-rust | grep -A 1 GNU_STACK
+ GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
+ 0x0000000000000000 0x0000000000000000 RW 0x10
+```
+Fig. 5. Checking if non-executable memory regions are enabled for a given
+binary.
+
+The presence of an element of type `PT_GNU_STACK` in the program header
+table with the `PF_X` (i.e., executable) flag unset indicates non-executable
+memory regions<sup id="fnref:3" role="doc-noteref"><a href="#fn:3"
+class="footnote">3</a></sup> are enabled for a given binary (see Fig. 5).
+Conversely, the presence of an element of type `PT_GNU_STACK` in the program
+header table with the `PF_X` flag set or the absence of an element of type
+`PT_GNU_STACK` in the program header table indicates non-executable memory
+regions are not enabled for a given binary.
+
+<small id="fn:3">3\. See the Appendix section for more information on why it
+affects other memory regions besides the stack. <a href="#fnref:3"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Stack clashing protection
+
+Stack clashing protection protects the stack from overlapping with another
+memory region—allowing arbitrary data in both to be overwritten using each
+other—by reading from the stack pages as the stack grows to cause a page
+fault when attempting to read from the guard page/region. This is also
+referred to as “stack probes” or “stack probing”.
+
+The Rust compiler supports stack clashing protection via stack probing, and
+enables it by default since version 1.20.0 (2017-08-31)[26]–[29].
+
+![Screenshot of IDA Pro listing cross references to __rust_probestack in hello-rust.](images/image1.png "Cross references to __rust_probestack in hello-rust.")
+Fig. 6. IDA Pro listing cross references to `__rust_probestack` in
+hello-rust.
+
+```rust
+fn hello() {
+ println!("Hello, world!");
+}
+
+fn main() {
+ let _: [u64; 1024] = [0; 1024];
+ hello();
+}
+```
+Fig 7. Modified hello-rust.
+
+![Screenshot of IDA Pro listing cross references to __rust_probestack in modified hello-rust.](images/image2.png "Cross references to __rust_probestack in modified hello-rust.")
+Fig. 8. IDA Pro listing cross references to `__rust_probestack` in modified
+hello-rust.
+
+To check if stack clashing protection is enabled for a given binary, search
+for cross references to `__rust_probestack`. The `__rust_probestack` is
+called in the prologue of functions whose stack size is larger than a page
+size (see Fig. 6), and can be forced for illustration purposes by modifying
+the hello-rust example as seen in Fig. 7 and Fig. 8.
+
+
+### Read-only relocations and immediate binding
+
+**Read-only relocations** protect segments containing relocations and
+relocation information (i.e., `.init_array`, `.fini_array`, `.dynamic`, and
+`.got`) from being overwritten by marking these segments read only. This is
+also referred to as “partial RELRO”.
+
+The Rust compiler supports read-only relocations, and enables it by default
+since version 1.21.0 (2017-10-12)[30], [31].
+
+```text
+$ readelf -l target/release/hello-rust | grep GNU_RELRO
+ GNU_RELRO 0x000000000002ee00 0x000000000002fe00 0x000000000002fe00
+```
+Fig. 9. Checking if read-only relocations is enabled for a given binary.
+
+The presence of an element of type `PT_GNU_RELRO` in the program header
+table indicates read-only relocations are enabled for a given binary (see
+Fig. 9). Conversely, the absence of an element of type `PT_GNU_RELRO` in the
+program header table indicates read-only relocations are not enabled for a
+given binary.
+
+**Immediate binding** protects additional segments containing relocations
+(i.e., `.got.plt`) from being overwritten by instructing the dynamic linker
+to perform all relocations before transferring control to the program during
+startup, so all segments containing relocations can be marked read only
+(when combined with read-only relocations). This is also referred to as
+“full RELRO”.
+
+The Rust compiler supports immediate binding, and enables it by default
+since version 1.21.0 (2017-10-12)[30], [31].
+
+```text
+$ readelf -d target/release/hello-rust | grep BIND_NOW
+ 0x000000000000001e (FLAGS) BIND_NOW
+```
+Fig. 10. Checking if immediate binding is enabled for a given binary.
+
+The presence of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW`
+flag<sup id="fnref:4" role="doc-noteref"><a href="#fn:4"
+class="footnote">4</a></sup> in the dynamic section indicates immediate
+binding is enabled for a given binary (see Fig. 10). Conversely, the absence
+of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` flag in the
+dynamic section indicates immediate binding is not enabled for a given
+binary.
+
+The presence of both an element of type `PT_GNU_RELRO` in the program header
+table and of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW`
+flag in the dynamic section indicates full RELRO is enabled for a given
+binary (see Fig. 9 and Fig. 10).
+
+<small id="fn:4">4\. And the `DF_1_NOW` flag for some link editors. <a
+href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Heap corruption protection
+
+Heap corruption protection protects memory allocated dynamically by
+performing several checks, such as checks for corrupted links between list
+elements, invalid pointers, invalid sizes, double/multiple “frees” of the
+same memory allocated, and many corner cases of these. These checks are
+implementation specific, and vary per allocator.
+
+[ARM Memory Tagging Extension
+(MTE)](https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/enhancing-memory-safety),
+when available, will provide hardware assistance for a probabilistic
+mitigation to detect memory safety violations by tagging memory allocations,
+and automatically checking that the correct tag is used on every memory
+access.
+
+Rust’s default allocator has historically been
+[jemalloc](http://jemalloc.net/), and it has long been the cause of issues
+and the subject of much discussion[32]–[38]. Consequently, it has been
+removed as the default allocator in favor of the operating system’s standard
+C library default allocator<sup id="fnref:5" role="doc-noteref"><a
+href="#fn:5" class="footnote">5</a></sup> since version 1.32.0
+(2019-01-17)[39].
+
+```ignore
+fn main() {
+ let mut x = Box::new([0; 1024]);
+
+ for i in 0..1026 {
+ unsafe {
+ let elem = x.get_unchecked_mut(i);
+ *elem = 0x4141414141414141u64;
+ }
+ }
+}
+```
+Fig. 11. hello-rust-heap program.
+
+```text
+$ cargo run
+ Compiling hello-rust-heap v0.1.0 (/home/rcvalle/hello-rust-heap)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.25s
+ Running `target/debug/hello-rust-heap`
+free(): invalid next size (normal)
+Aborted
+```
+Fig. 12. Build and execution of hello-rust-heap with debug assertions
+enabled.
+
+```text
+$ cargo run --release
+ Compiling hello-rust-heap v0.1.0 (/home/rcvalle/hello-rust-heap)
+ Finished release [optimized] target(s) in 0.25s
+ Running `target/release/hello-rust-heap`
+free(): invalid next size (normal)
+Aborted
+```
+Fig. 13. Build and execution of hello-rust-heap with debug assertions
+disabled.
+
+Heap corruption checks are being performed when using the default allocator
+(i.e., the GNU Allocator) as seen in Fig. 12 and Fig. 13.
+
+<small id="fn:5">5\. Linux's standard C library default allocator is the GNU
+Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram
+Gloger, which in turn is derived from dlmalloc (Doug Lea malloc) by Doug
+Lea. <a href="#fnref:5" class="reversefootnote"
+role="doc-backlink">↩</a></small>
+
+
+### Stack smashing protection
+
+Stack smashing protection protects programs from stack-based buffer
+overflows by inserting a random guard value between local variables and the
+saved return instruction pointer, and checking if this value has changed
+when returning from a function. This is also known as “Stack Protector” or
+“Stack Smashing Protector (SSP)”.
+
+The Rust compiler does not support stack smashing protection. However, more
+comprehensive alternatives to stack smashing protection exist, such as
+shadow and safe stack (see backward-edge control flow protection).
+
+![Screenshot of IDA Pro listing cross references to __stack_chk_fail in hello-rust.](images/image3.png "Cross references to __stack_chk_fail in hello-rust.")
+Fig. 14. IDA Pro listing cross references to `__stack_chk_fail` in
+hello-rust.
+
+To check if stack smashing protection is enabled for a given binary, search
+for cross references to `__stack_chk_fail`. The only cross references to
+`__stack_chk_fail` in hello-rust are from the statically-linked libbacktrace
+library (see Fig. 14).
+
+
+### Forward-edge control flow protection
+
+Forward-edge control flow protection protects programs from having its
+control flow changed/hijacked by performing checks to ensure that
+destinations of indirect branches are one of their valid destinations in the
+control flow graph. The comprehensiveness of these checks vary per
+implementation. This is also known as “forward-edge control flow integrity
+(CFI)”.
+
+Newer processors provide hardware assistance for forward-edge control flow
+protection, such as ARM Branch Target Identification (BTI), ARM Pointer
+Authentication, and Intel Indirect Branch Tracking (IBT) as part of Intel
+Control-flow Enforcement Technology (CET). However, ARM BTI and Intel IBT
+-based implementations are less comprehensive than software-based
+implementations such as [LLVM ControlFlowIntegrity
+(CFI)](https://clang.llvm.org/docs/ControlFlowIntegrity.html), and the
+commercially available [grsecurity/PaX Reuse Attack Protector
+(RAP)](https://grsecurity.net/rap_faq).
+
+The Rust compiler does not support forward-edge control flow protection on
+Linux<sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
+class="footnote">6</a></sup>. There is work currently ongoing to add support
+for the [sanitizers](https://github.com/google/sanitizers)[40], which may or
+may not include support for LLVM CFI.
+
+```text
+$ readelf -s target/release/hello-rust | grep __cfi_init
+```
+Fig. 15. Checking if LLVM CFI is enabled for a given binary.
+
+The presence of the `__cfi_init` symbol (and references to `__cfi_check`)
+indicates that LLVM CFI (i.e., forward-edge control flow protection) is
+enabled for a given binary. Conversely, the absence of the `__cfi_init`
+symbol (and references to `__cfi_check`) indicates that LLVM CFI is not
+enabled for a given binary (see Fig. 15).
+
+<small id="fn:6">6\. It supports Control Flow Guard (CFG) on Windows (see
+<https://github.com/rust-lang/rust/issues/68793>). <a href="#fnref:6"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Backward-edge control flow protection
+
+**Shadow stack** protects saved return instruction pointers from being
+overwritten by storing a copy of them on a separate (shadow) stack, and
+using these copies as authoritative values when returning from functions.
+This is also known as “ShadowCallStack” and “Return Flow Guard”, and is
+considered an implementation of backward-edge control flow protection (or
+“backward-edge CFI”).
+
+**Safe stack** protects not only the saved return instruction pointers, but
+also register spills and some local variables from being overwritten by
+storing unsafe variables, such as large arrays, on a separate (unsafe)
+stack, and using these unsafe variables on the separate stack instead. This
+is also known as “SafeStack”, and is also considered an implementation of
+backward-edge control flow protection.
+
+Both shadow and safe stack are intended to be a more comprehensive
+alternatives to stack smashing protection as they protect the saved return
+instruction pointers (and other data in the case of safe stack) from
+arbitrary writes and non-linear out-of-bounds writes.
+
+Newer processors provide hardware assistance for backward-edge control flow
+protection, such as ARM Pointer Authentication, and Intel Shadow Stack as
+part of Intel CET.
+
+The Rust compiler does not support shadow or safe stack. There is work
+currently ongoing to add support for the sanitizers[40], which may or may
+not include support for safe stack<sup id="fnref:7" role="doc-noteref"><a
+href="#fn:7" class="footnote">7</a></sup>.
+
+```text
+$ readelf -s target/release/hello-rust | grep __safestack_init
+```
+Fig. 16. Checking if LLVM SafeStack is enabled for a given binary.
+
+The presence of the `__safestack_init` symbol indicates that LLVM SafeStack
+is enabled for a given binary. Conversely, the absence of the
+`__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a
+given binary (see Fig. 16).
+
+<small id="fn:7">7\. The shadow stack implementation for the AMD64
+architecture and equivalent in LLVM was removed due to performance and
+security issues. <a href="#fnref:7" class="reversefootnote"
+role="doc-backlink">↩</a></small>
+
+
+## Appendix
+
+As of the latest version of the [Linux Standard Base (LSB) Core
+Specification](https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/progheader.html),
+the `PT_GNU_STACK` program header indicates whether the stack should be
+executable, and the absence of this header indicates that the stack should
+be executable. However, the Linux kernel currently sets the
+`READ_IMPLIES_EXEC` personality upon loading any executable with the
+`PT_GNU_STACK` program header and the `PF_X `flag set or with the absence of
+this header, resulting in not only the stack, but also all readable virtual
+memory mappings being executable.
+
+An attempt to fix this [was made in
+2012](https://lore.kernel.org/lkml/f298f914-2239-44e4-8aa1-a51282e7fac0@zmail15.collab.prod.int.phx2.redhat.com/),
+and another [was made in
+2020](https://lore.kernel.org/kernel-hardening/20200327064820.12602-1-keescook@chromium.org/).
+The former never landed, and the latter partially fixed it, but introduced
+other issues—the absence of the `PT_GNU_STACK` program header still causes
+not only the stack, but also all readable virtual memory mappings to be
+executable in some architectures, such as IA-32 and equivalent (or causes
+the stack to be non-executable in some architectures, such as AMD64 and
+equivalent, contradicting the LSB).
+
+The `READ_IMPLIES_EXEC` personality needs to be completely separated from
+the `PT_GNU_STACK` program header by having a separate option for it (or
+setarch -X could just be used whenever `READ_IMPLIES_EXEC` is needed), and
+the absence of the `PT_GNU_STACK` program header needs to have more secure
+defaults (unrelated to `READ_IMPLIES_EXEC`).
+
+
+## References
+
+1. D. Hosfelt. “Fearless security: memory safety.” Mozilla Hacks.
+ <https://hacks.mozilla.org/2019/01/fearless-security-memory-safety/>.
+
+2. D. Hosfelt. “Fearless security: thread safety.” Mozilla Hacks.
+ <https://hacks.mozilla.org/2019/02/fearless-security-thread-safety/>.
+
+3. S. Klabnik and C. Nichols. “What Is Ownership?.” The Rust Programming
+ Language. <https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html>.
+
+4. S. Klabnik and C. Nichols. “References and Borrowing.” The Rust
+ Programming Language.
+ <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html>.
+
+5. S. Klabnik and C. Nichols. “The Slice Type.” The Rust Programming
+ Language. <https://doc.rust-lang.org/book/ch04-03-slices.html>.
+
+6. S. Klabnik and C. Nichols. “Unsafe Rust.” The Rust Programming Language.
+ <https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html>.
+
+7. S. Davidoff. “How Rust’s standard library was vulnerable for years and
+ nobody noticed.” Medium.
+ <https://medium.com/@shnatsel/how-rusts-standard-library-was-vulnerable-for-years-and-nobody-noticed-aebf0503c3d6>.
+
+8. “Improper restriction of operations within the bounds of a memory buffer
+ (CWE-119).” MITRE CWE List.
+ <https://cwe.mitre.org/data/definitions/119.html>.
+
+9. “Concurrency issues (CWE-557).” MITRE CWE List.
+ <https://cwe.mitre.org/data/definitions/557.html>.
+
+10. K. McAllister. “Memory exploit mitigations #15179.” GitHub.
+ <https://github.com/rust-lang/rust/issues/15179>.
+
+11. K. McAllister. “RFC: Memory exploit mitigation #145.” GitHub.
+ <https://github.com/rust-lang/rfcs/pull/145>.
+
+12. K. McAllister. “RFC: Memory exploit mitigation.” GitHub.
+ <https://github.com/kmcallister/rfcs/blob/hardening/active/0000-memory-exploit-mitigation.md>.
+
+13. D. Micay. “Enable PIE by default on Linux for full ASLR #16340.” GitHub.
+ <https://github.com/rust-lang/rust/pull/16340>.
+
+14. N. Matsakis. “Integer overflow #560.” GitHub.
+ <https://github.com/rust-lang/rfcs/pull/560>.
+
+15. G. Lehel and N. Matsakis. “Integer overflow.” GitHub.
+ <https://rust-lang.github.io/rfcs/0560-integer-overflow.html>.
+
+16. A. Turon. “Tracking issue for integer overflow (RFC 560) #22020.”
+ GitHub. <https://github.com/rust-lang/rust/issues/22020>.
+
+17. H. Wilson. “Myths and legends about integer overflow in Rust.” Huon on
+ the Internet.
+ <http://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/>.
+
+18. B. Anderson. “Stabilize -C overflow-checks #1535.” GitHub.
+ <https://github.com/rust-lang/rfcs/pull/1535>.
+
+19. B. Anderson. “Stable overflow checks.” GitHub.
+ <https://github.com/brson/rfcs/blob/overflow/text/0000-stable-overflow-checks.md>.
+
+20. N. Froyd. “Add -C overflow-checks option #40037.” GitHub.
+ <https://github.com/rust-lang/rust/pull/40037>.
+
+21. R. Á. de Espíndola. “rustc requires executable stack #798.” GitHub.
+ <https://github.com/rust-lang/rust/issues/798>.
+
+22. A. Seipp. “Make sure librustrt.so is linked with a non-executable stack.
+ #1066.” GitHub. <https://github.com/rust-lang/rust/pull/1066>.
+
+23. D. Micay. “Rust binaries should not have an executable stack #5643.”
+ GitHub. <https://github.com/rust-lang/rust/issues/5643>.
+
+24. D. Micay. “Mark the assembly object stacks as non-executable #5647.”
+ GitHub. <https://github.com/rust-lang/rust/pull/5647>.
+
+25. A. Clark. “Explicitly disable stack execution on linux and bsd #30859.”
+ GitHub. <https://github.com/rust-lang/rust/pull/30859>.
+
+26. “Replace stack overflow checking with stack probes #16012.” GitHub.
+ <https://github.com/rust-lang/rust/issues/16012>.
+
+27. B. Striegel. “Extend stack probe support to non-tier-1 platforms, and
+ clarify policy for mitigating LLVM-dependent unsafety #43241.” GitHub.
+ <https://github.com/rust-lang/rust/issues/43241>.
+
+28. A. Crichton. “rustc: Implement stack probes for x86 #42816.” GitHub.
+ <https://github.com/rust-lang/rust/pull/42816>.
+
+29. A. Crichton. “Add \_\_rust\_probestack intrinsic #175.” GitHub.
+ <https://github.com/rust-lang/compiler-builtins/pull/175>.
+
+30. B. Anderson. “Consider applying -Wl,-z,relro or -Wl,-z,relro,-z,now by
+ default #29877.” GitHub. <https://github.com/rust-lang/rust/issues/29877>.
+
+31. J. Löthberg. “Add support for full RELRO #43170.” GitHub.
+ <https://github.com/rust-lang/rust/pull/43170>.
+
+32. N. Matsakis. “Allocators in Rust.” Baby Steps.
+ <http://smallcultfollowing.com/babysteps/blog/2014/11/14/allocators-in-rust/>.
+
+33. A. Crichton. “RFC: Allow changing the default allocator #1183.” GitHub.
+ <https://github.com/rust-lang/rfcs/pull/1183>.
+
+34. A. Crichton. “RFC: Swap out jemalloc.” GitHub.
+ <https://rust-lang.github.io/rfcs/1183-swap-out-jemalloc.html>.
+
+35. A. Crichton. “Tracking issue for changing the global, default allocator
+ (RFC 1974) #27389.” GitHub.
+ <https://github.com/rust-lang/rust/issues/27389>.
+
+36. S. Fackler. “Prepare global allocators for stabilization #1974.” GitHub.
+ <https://github.com/rust-lang/rfcs/pull/1974>.
+
+37. A. Crichton. “RFC: Global allocators.” GitHub.
+ <https://rust-lang.github.io/rfcs/1974-global-allocators.html>.
+
+38. B. Anderson. “Switch the default global allocator to System, remove
+ alloc\_jemalloc, use jemallocator in rustc #36963.” GitHub.
+ <https://github.com/rust-lang/rust/issues/36963>.
+
+39. A. Crichton. “Remove the alloc\_jemalloc crate #55238.” GitHub.
+ <https://github.com/rust-lang/rust/pull/55238>.
+
+40. J. Aparicio. 2017. “Tracking issue for sanitizer support #39699.”
+ <https://github.com/rust-lang/rust/issues/39699>.
target | std | host | notes
-------|-----|------|-------
+`aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64
`aarch64-apple-tvos` | * | | ARM64 tvOS
-`aarch64-unknown-cloudabi` | ✓ | | ARM64 CloudABI
`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
`aarch64-unknown-hermit` | ? | |
`aarch64-unknown-netbsd` | ? | |
`armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
`armv6-unknown-netbsd-eabihf` | ? | |
`armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8
-`armv7-unknown-cloudabi-eabihf` | ✓ | | ARMv7 CloudABI, hardfloat
`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
`armv7-unknown-netbsd-eabihf` | ? | |
`armv7-wrs-vxworks-eabihf` | ? | |
`i386-apple-ios` | ✓ | | 32-bit x86 iOS
`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
`i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support
-`i686-unknown-cloudabi` | ✓ | | 32-bit CloudABI
`i686-unknown-uefi` | ? | | 32-bit UEFI
`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
`i686-unknown-netbsd` | ✓ | | NetBSD/i386 with SSE2
`thumbv7a-uwp-windows-msvc` | ✓ | |
`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL
`thumbv4t-none-eabi` | * | | ARMv4T T32
-`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst
+`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64
`x86_64-apple-tvos` | * | | x86 64-bit tvOS
`x86_64-linux-kernel` | * | | Linux kernel modules
`x86_64-pc-solaris` | ? | |
`x86_64-pc-windows-msvc` | ✓ | | 64-bit Windows XP support
-`x86_64-unknown-cloudabi` | ✓ | | 64-bit CloudABI
`x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
`x86_64-unknown-hermit` | ? | |
--- /dev/null
+# `auto_traits`
+
+The tracking issue for this feature is [#13231]
+
+[#13231]: https://github.com/rust-lang/rust/issues/13231
+
+----
+
+The `auto_traits` feature gate allows you to define auto traits.
+
+Auto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits
+that are automatically implemented for every type, unless the type, or a type it contains,
+has explicitly opted out via a negative impl. (Negative impls are separately controlled
+by the `negative_impls` feature.)
+
+[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
+[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+
+```rust,ignore
+impl !Trait for Type
+```
+
+Example:
+
+```rust
+#![feature(negative_impls)]
+#![feature(auto_traits)]
+
+auto trait Valid {}
+
+struct True;
+struct False;
+
+impl !Valid for False {}
+
+struct MaybeValid<T>(T);
+
+fn must_be_valid<T: Valid>(_t: T) { }
+
+fn main() {
+ // works
+ must_be_valid( MaybeValid(True) );
+
+ // compiler error - trait bound not satisfied
+ // must_be_valid( MaybeValid(False) );
+}
+```
+
+## Automatic trait implementations
+
+When a type is declared as an `auto trait`, we will automatically
+create impls for every struct/enum/union, unless an explicit impl is
+provided. These automatic impls contain a where clause for each field
+of the form `T: AutoTrait`, where `T` is the type of the field and
+`AutoTrait` is the auto trait in question. As an example, consider the
+struct `List` and the auto trait `Send`:
+
+```rust
+struct List<T> {
+ data: T,
+ next: Option<Box<List<T>>>,
+}
+```
+
+Presuming that there is no explicit impl of `Send` for `List`, the
+compiler will supply an automatic impl of the form:
+
+```rust
+struct List<T> {
+ data: T,
+ next: Option<Box<List<T>>>,
+}
+
+unsafe impl<T> Send for List<T>
+where
+ T: Send, // from the field `data`
+ Option<Box<List<T>>>: Send, // from the field `next`
+{ }
+```
+
+Explicit impls may be either positive or negative. They take the form:
+
+```rust,ignore
+impl<...> AutoTrait for StructName<..> { }
+impl<...> !AutoTrait for StructName<..> { }
+```
+
+## Coinduction: Auto traits permit cyclic matching
+
+Unlike ordinary trait matching, auto traits are **coinductive**. This
+means, in short, that cycles which occur in trait matching are
+considered ok. As an example, consider the recursive struct `List`
+introduced in the previous section. In attempting to determine whether
+`List: Send`, we would wind up in a cycle: to apply the impl, we must
+show that `Option<Box<List>>: Send`, which will in turn require
+`Box<List>: Send` and then finally `List: Send` again. Under ordinary
+trait matching, this cycle would be an error, but for an auto trait it
+is considered a successful match.
+
+## Items
+
+Auto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations.
+
+## Supertraits
+
+Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile.
+
+++ /dev/null
-# `optin_builtin_traits`
-
-The tracking issue for this feature is [#13231]
-
-[#13231]: https://github.com/rust-lang/rust/issues/13231
-
-----
-
-The `optin_builtin_traits` feature gate allows you to define auto traits.
-
-Auto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits
-that are automatically implemented for every type, unless the type, or a type it contains,
-has explicitly opted out via a negative impl. (Negative impls are separately controlled
-by the `negative_impls` feature.)
-
-[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
-[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
-
-```rust,ignore
-impl !Trait for Type
-```
-
-Example:
-
-```rust
-#![feature(negative_impls)]
-#![feature(optin_builtin_traits)]
-
-auto trait Valid {}
-
-struct True;
-struct False;
-
-impl !Valid for False {}
-
-struct MaybeValid<T>(T);
-
-fn must_be_valid<T: Valid>(_t: T) { }
-
-fn main() {
- // works
- must_be_valid( MaybeValid(True) );
-
- // compiler error - trait bound not satisfied
- // must_be_valid( MaybeValid(False) );
-}
-```
-
-## Automatic trait implementations
-
-When a type is declared as an `auto trait`, we will automatically
-create impls for every struct/enum/union, unless an explicit impl is
-provided. These automatic impls contain a where clause for each field
-of the form `T: AutoTrait`, where `T` is the type of the field and
-`AutoTrait` is the auto trait in question. As an example, consider the
-struct `List` and the auto trait `Send`:
-
-```rust
-struct List<T> {
- data: T,
- next: Option<Box<List<T>>>,
-}
-```
-
-Presuming that there is no explicit impl of `Send` for `List`, the
-compiler will supply an automatic impl of the form:
-
-```rust
-struct List<T> {
- data: T,
- next: Option<Box<List<T>>>,
-}
-
-unsafe impl<T> Send for List<T>
-where
- T: Send, // from the field `data`
- Option<Box<List<T>>>: Send, // from the field `next`
-{ }
-```
-
-Explicit impls may be either positive or negative. They take the form:
-
-```rust,ignore
-impl<...> AutoTrait for StructName<..> { }
-impl<...> !AutoTrait for StructName<..> { }
-```
-
-## Coinduction: Auto traits permit cyclic matching
-
-Unlike ordinary trait matching, auto traits are **coinductive**. This
-means, in short, that cycles which occur in trait matching are
-considered ok. As an example, consider the recursive struct `List`
-introduced in the previous section. In attempting to determine whether
-`List: Send`, we would wind up in a cycle: to apply the impl, we must
-show that `Option<Box<List>>: Send`, which will in turn require
-`Box<List>: Send` and then finally `List: Send` again. Under ordinary
-trait matching, this cycle would be an error, but for an auto trait it
-is considered a successful match.
-
-## Items
-
-Auto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations.
-
-## Supertraits
-
-Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile.
-
yield "borrow", self.borrow
-# Yields children (in a provider's sense of the word) for a tree headed by a BoxedNode.
-# In particular, yields each key/value pair in the node and in any child nodes.
-def children_of_node(boxed_node, height):
- def cast_to_internal(node):
- internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1)
- internal_type = lookup_type(internal_type_name)
- return node.cast(internal_type.pointer())
-
- node_ptr = unwrap_unique_or_non_null(boxed_node["ptr"])
- leaf = node_ptr.dereference()
- keys = leaf["keys"]
- vals = leaf["vals"]
- edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None
- length = int(leaf["len"])
-
- for i in xrange(0, length + 1):
- if height > 0:
- boxed_child_node = edges[i]["value"]["value"]
- for child in children_of_node(boxed_child_node, height - 1):
- yield child
- if i < length:
- # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
- key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else "()"
- val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else "()"
- yield key, val
-
-
-# Yields children for a BTreeMap.
-def children_of_map(map):
+# Yields children (in a provider's sense of the word) for a BTreeMap.
+def children_of_btree_map(map):
+ # Yields each key/value pair in the node and in any child nodes.
+ def children_of_node(node_ptr, height):
+ def cast_to_internal(node):
+ internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1)
+ internal_type = lookup_type(internal_type_name)
+ return node.cast(internal_type.pointer())
+
+ if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"):
+ # BACKCOMPAT: rust 1.49
+ node_ptr = node_ptr["ptr"]
+ node_ptr = unwrap_unique_or_non_null(node_ptr)
+ leaf = node_ptr.dereference()
+ keys = leaf["keys"]
+ vals = leaf["vals"]
+ edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None
+ length = leaf["len"]
+
+ for i in xrange(0, length + 1):
+ if height > 0:
+ child_ptr = edges[i]["value"]["value"]
+ for child in children_of_node(child_ptr, height - 1):
+ yield child
+ if i < length:
+ # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
+ key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else "()"
+ val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else "()"
+ yield key, val
+
if map["length"] > 0:
root = map["root"]
if root.type.name.startswith("core::option::Option<"):
root = root.cast(gdb.lookup_type(root.type.name[21:-1]))
- boxed_root_node = root["node"]
+ node_ptr = root["node"]
height = root["height"]
- for child in children_of_node(boxed_root_node, height):
+ for child in children_of_node(node_ptr, height):
yield child
def children(self):
inner_map = self.valobj["map"]
- for i, (child, _) in enumerate(children_of_map(inner_map)):
+ for i, (child, _) in enumerate(children_of_btree_map(inner_map)):
yield "[{}]".format(i), child
@staticmethod
return "BTreeMap(size={})".format(self.valobj["length"])
def children(self):
- for i, (key, val) in enumerate(children_of_map(self.valobj)):
+ for i, (key, val) in enumerate(children_of_btree_map(self.valobj)):
yield "key{}".format(i), key
yield "val{}".format(i), val
let attrs = merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone);
cx.renderinfo.borrow_mut().inlined.insert(did);
- let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name), kind, cx);
+ let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name.clean(cx)), kind, cx);
ret.push(clean::Item { attrs, ..what_rustc_thinks });
Some(ret)
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::bug;
}
}
}
- return prim.map(|p| (def_id, p, attrs));
+ return prim.map(|p| (def_id, p));
}
None
};
hir::ItemKind::Use(ref path, hir::UseKind::Single)
if item.vis.node.is_pub() =>
{
- as_primitive(path.res).map(|(_, prim, attrs)| {
+ as_primitive(path.res).map(|(_, prim)| {
// Pretend the primitive is local.
- (cx.tcx.hir().local_def_id(id.id).to_def_id(), prim, attrs)
+ (cx.tcx.hir().local_def_id(id.id).to_def_id(), prim)
})
}
_ => None,
}
}
}
- return keyword.map(|p| (def_id, p, attrs));
+ return keyword.map(|p| (def_id, p));
}
None
};
hir::ItemKind::Use(ref path, hir::UseKind::Single)
if item.vis.node.is_pub() =>
{
- as_keyword(path.res).map(|(_, prim, attrs)| {
- (cx.tcx.hir().local_def_id(id.id).to_def_id(), prim, attrs)
+ as_keyword(path.res).map(|(_, prim)| {
+ (cx.tcx.hir().local_def_id(id.id).to_def_id(), prim)
})
}
_ => None,
let attrs = self.attrs.clean(cx);
let mut items: Vec<Item> = vec![];
- items.extend(self.extern_crates.iter().flat_map(|x| x.clean(cx)));
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
- items.extend(self.structs.iter().map(|x| x.clean(cx)));
- items.extend(self.unions.iter().map(|x| x.clean(cx)));
- items.extend(self.enums.iter().map(|x| x.clean(cx)));
- items.extend(self.fns.iter().map(|x| x.clean(cx)));
items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
items.extend(self.mods.iter().map(|x| x.clean(cx)));
- items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
- items.extend(self.opaque_tys.iter().map(|x| x.clean(cx)));
- items.extend(self.statics.iter().map(|x| x.clean(cx)));
- items.extend(self.constants.iter().map(|x| x.clean(cx)));
- items.extend(self.traits.iter().map(|x| x.clean(cx)));
- items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
+ items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
items.extend(self.macros.iter().map(|x| x.clean(cx)));
- items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
- items.extend(self.trait_aliases.iter().map(|x| x.clean(cx)));
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
}
}
+fn clean_fn_or_proc_macro(
+ item: &hir::Item<'_>,
+ sig: &'a hir::FnSig<'a>,
+ generics: &'a hir::Generics<'a>,
+ body_id: hir::BodyId,
+ name: &mut Symbol,
+ cx: &DocContext<'_>,
+) -> ItemKind {
+ let macro_kind = item.attrs.iter().find_map(|a| {
+ if a.has_name(sym::proc_macro) {
+ Some(MacroKind::Bang)
+ } else if a.has_name(sym::proc_macro_derive) {
+ Some(MacroKind::Derive)
+ } else if a.has_name(sym::proc_macro_attribute) {
+ Some(MacroKind::Attr)
+ } else {
+ None
+ }
+ });
+ match macro_kind {
+ Some(kind) => {
+ if kind == MacroKind::Derive {
+ *name = item
+ .attrs
+ .lists(sym::proc_macro_derive)
+ .find_map(|mi| mi.ident())
+ .expect("proc-macro derives require a name")
+ .name;
+ }
+
+ let mut helpers = Vec::new();
+ for mi in item.attrs.lists(sym::proc_macro_derive) {
+ if !mi.has_name(sym::attributes) {
+ continue;
+ }
+
+ if let Some(list) = mi.meta_item_list() {
+ for inner_mi in list {
+ if let Some(ident) = inner_mi.ident() {
+ helpers.push(ident.name);
+ }
+ }
+ }
+ }
+ ProcMacroItem(ProcMacro { kind, helpers: helpers.clean(cx) })
+ }
+ None => {
+ let mut func = (sig, generics, body_id).clean(cx);
+ let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id();
+ func.header.constness =
+ if is_const_fn(cx.tcx, def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
+ hir::Constness::Const
+ } else {
+ hir::Constness::NotConst
+ };
+ FunctionItem(func)
+ }
+ }
+}
+
impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
fn clean(&self, cx: &DocContext<'_>) -> Function {
let (generics, decl) =
}
}
-impl Clean<Item> for doctree::Function<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- let (generics, decl) =
- enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx)));
-
- let did = cx.tcx.hir().local_def_id(self.id).to_def_id();
- let constness = if is_const_fn(cx.tcx, did) && !is_unstable_const_fn(cx.tcx, did).is_some()
- {
- hir::Constness::Const
- } else {
- hir::Constness::NotConst
- };
- let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
- Item::from_def_id_and_parts(
- did,
- Some(self.name),
- FunctionItem(Function {
- decl,
- generics,
- header: hir::FnHeader { constness, ..self.header },
- all_types,
- ret_types,
- }),
- cx,
- )
- }
-}
-
impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
fn clean(&self, cx: &DocContext<'_>) -> Arguments {
Arguments {
}
}
-impl Clean<Item> for doctree::Trait<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- let attrs = self.attrs.clean(cx);
- let is_spotlight = attrs.has_doc_flag(sym::spotlight);
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- TraitItem(Trait {
- unsafety: self.unsafety,
- items: self.items.iter().map(|ti| ti.clean(cx)).collect(),
- generics: self.generics.clean(cx),
- bounds: self.bounds.clean(cx),
- is_spotlight,
- is_auto: self.is_auto.clean(cx),
- }),
- cx,
- )
- }
-}
-
-impl Clean<Item> for doctree::TraitAlias<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- TraitAliasItem(TraitAlias {
- generics: self.generics.clean(cx),
- bounds: self.bounds.clean(cx),
- }),
- cx,
- )
- }
-}
-
impl Clean<bool> for hir::IsAuto {
fn clean(&self, _: &DocContext<'_>) -> bool {
match *self {
impl Clean<Item> for hir::TraitItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let local_did = cx.tcx.hir().local_def_id(self.hir_id).to_def_id();
- let inner = match self.kind {
- hir::TraitItemKind::Const(ref ty, default) => {
- AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e)))
- }
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- let mut m = (sig, &self.generics, body).clean(cx);
- if m.header.constness == hir::Constness::Const
- && is_unstable_const_fn(cx.tcx, local_did).is_some()
- {
- m.header.constness = hir::Constness::NotConst;
+ cx.with_param_env(local_did, || {
+ let inner = match self.kind {
+ hir::TraitItemKind::Const(ref ty, default) => {
+ AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e)))
}
- MethodItem(m, None)
- }
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
- let (generics, decl) = enter_impl_trait(cx, || {
- (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
- });
- let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
- let mut t = Function { header: sig.header, decl, generics, all_types, ret_types };
- if t.header.constness == hir::Constness::Const
- && is_unstable_const_fn(cx.tcx, local_did).is_some()
- {
- t.header.constness = hir::Constness::NotConst;
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+ let mut m = (sig, &self.generics, body).clean(cx);
+ if m.header.constness == hir::Constness::Const
+ && is_unstable_const_fn(cx.tcx, local_did).is_some()
+ {
+ m.header.constness = hir::Constness::NotConst;
+ }
+ MethodItem(m, None)
}
- TyMethodItem(t)
- }
- hir::TraitItemKind::Type(ref bounds, ref default) => {
- AssocTypeItem(bounds.clean(cx), default.clean(cx))
- }
- };
- Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx)
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
+ let (generics, decl) = enter_impl_trait(cx, || {
+ (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
+ });
+ let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
+ let mut t =
+ Function { header: sig.header, decl, generics, all_types, ret_types };
+ if t.header.constness == hir::Constness::Const
+ && is_unstable_const_fn(cx.tcx, local_did).is_some()
+ {
+ t.header.constness = hir::Constness::NotConst;
+ }
+ TyMethodItem(t)
+ }
+ hir::TraitItemKind::Type(ref bounds, ref default) => {
+ AssocTypeItem(bounds.clean(cx), default.clean(cx))
+ }
+ };
+ Item::from_def_id_and_parts(local_did, Some(self.ident.name.clean(cx)), inner, cx)
+ })
}
}
impl Clean<Item> for hir::ImplItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let local_did = cx.tcx.hir().local_def_id(self.hir_id).to_def_id();
- let inner = match self.kind {
- hir::ImplItemKind::Const(ref ty, expr) => {
- AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr)))
- }
- hir::ImplItemKind::Fn(ref sig, body) => {
- let mut m = (sig, &self.generics, body).clean(cx);
- if m.header.constness == hir::Constness::Const
- && is_unstable_const_fn(cx.tcx, local_did).is_some()
- {
- m.header.constness = hir::Constness::NotConst;
+ cx.with_param_env(local_did, || {
+ let inner = match self.kind {
+ hir::ImplItemKind::Const(ref ty, expr) => {
+ AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr)))
}
- MethodItem(m, Some(self.defaultness))
- }
- hir::ImplItemKind::TyAlias(ref ty) => {
- let type_ = ty.clean(cx);
- let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
- TypedefItem(Typedef { type_, generics: Generics::default(), item_type }, true)
- }
- };
- Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx)
+ hir::ImplItemKind::Fn(ref sig, body) => {
+ let mut m = (sig, &self.generics, body).clean(cx);
+ if m.header.constness == hir::Constness::Const
+ && is_unstable_const_fn(cx.tcx, local_did).is_some()
+ {
+ m.header.constness = hir::Constness::NotConst;
+ }
+ MethodItem(m, Some(self.defaultness))
+ }
+ hir::ImplItemKind::TyAlias(ref ty) => {
+ let type_ = ty.clean(cx);
+ let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
+ TypedefItem(Typedef { type_, generics: Generics::default(), item_type }, true)
+ }
+ };
+ Item::from_def_id_and_parts(local_did, Some(self.ident.name.clean(cx)), inner, cx)
+ })
}
}
}
};
- Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), kind, cx)
+ Item::from_def_id_and_parts(self.def_id, Some(self.ident.name.clean(cx)), kind, cx)
+ }
+}
+
+fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type {
+ use rustc_hir::GenericParamCount;
+ let hir::Ty { hir_id, span, ref kind } = *hir_ty;
+ let qpath = match kind {
+ hir::TyKind::Path(qpath) => qpath,
+ _ => unreachable!(),
+ };
+
+ match qpath {
+ hir::QPath::Resolved(None, ref path) => {
+ if let Res::Def(DefKind::TyParam, did) = path.res {
+ if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() {
+ return new_ty;
+ }
+ if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) {
+ return ImplTrait(bounds);
+ }
+ }
+
+ let mut alias = None;
+ if let Res::Def(DefKind::TyAlias, def_id) = path.res {
+ // Substitute private type aliases
+ if let Some(def_id) = def_id.as_local() {
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ if !cx.renderinfo.borrow().access_levels.is_exported(def_id.to_def_id()) {
+ alias = Some(&cx.tcx.hir().expect_item(hir_id).kind);
+ }
+ }
+ };
+
+ if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias {
+ let provided_params = &path.segments.last().expect("segments were empty");
+ let mut ty_substs = FxHashMap::default();
+ let mut lt_substs = FxHashMap::default();
+ let mut ct_substs = FxHashMap::default();
+ let generic_args = provided_params.generic_args();
+ {
+ let mut indices: GenericParamCount = Default::default();
+ for param in generics.params.iter() {
+ match param.kind {
+ hir::GenericParamKind::Lifetime { .. } => {
+ let mut j = 0;
+ let lifetime = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) => {
+ if indices.lifetimes == j {
+ return Some(lt);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(lt) = lifetime.cloned() {
+ let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let cleaned = if !lt.is_elided() {
+ lt.clean(cx)
+ } else {
+ self::types::Lifetime::elided()
+ };
+ lt_substs.insert(lt_def_id.to_def_id(), cleaned);
+ }
+ indices.lifetimes += 1;
+ }
+ hir::GenericParamKind::Type { ref default, .. } => {
+ let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let type_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Type(ty) => {
+ if indices.types == j {
+ return Some(ty);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ty) = type_ {
+ ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx));
+ } else if let Some(default) = *default {
+ ty_substs
+ .insert(ty_param_def_id.to_def_id(), default.clean(cx));
+ }
+ indices.types += 1;
+ }
+ hir::GenericParamKind::Const { .. } => {
+ let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let const_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Const(ct) => {
+ if indices.consts == j {
+ return Some(ct);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ct) = const_ {
+ ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx));
+ }
+ // FIXME(const_generics:defaults)
+ indices.consts += 1;
+ }
+ }
+ }
+ }
+ return cx.enter_alias(ty_substs, lt_substs, ct_substs, || ty.clean(cx));
+ }
+ resolve_type(cx, path.clean(cx), hir_id)
+ }
+ hir::QPath::Resolved(Some(ref qself), ref p) => {
+ // Try to normalize `<X as Y>::T` to a type
+ let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+ if let Some(normalized_value) = normalize(cx, ty) {
+ return normalized_value.clean(cx);
+ }
+
+ let segments = if p.is_global() { &p.segments[1..] } else { &p.segments };
+ let trait_segments = &segments[..segments.len() - 1];
+ let trait_path = self::Path {
+ global: p.is_global(),
+ res: Res::Def(
+ DefKind::Trait,
+ cx.tcx.associated_item(p.res.def_id()).container.id(),
+ ),
+ segments: trait_segments.clean(cx),
+ };
+ Type::QPath {
+ name: p.segments.last().expect("segments were empty").ident.name.clean(cx),
+ self_type: box qself.clean(cx),
+ trait_: box resolve_type(cx, trait_path, hir_id),
+ }
+ }
+ hir::QPath::TypeRelative(ref qself, ref segment) => {
+ let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+ let res = if let ty::Projection(proj) = ty.kind() {
+ Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id)
+ } else {
+ Res::Err
+ };
+ let trait_path = hir::Path { span, res, segments: &[] };
+ Type::QPath {
+ name: segment.ident.name.clean(cx),
+ self_type: box qself.clean(cx),
+ trait_: box resolve_type(cx, trait_path.clean(cx), hir_id),
+ }
+ }
+ hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
}
}
unreachable!()
}
}
- TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
- if let Res::Def(DefKind::TyParam, did) = path.res {
- if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() {
- return new_ty;
- }
- if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) {
- return ImplTrait(bounds);
- }
- }
-
- let mut alias = None;
- if let Res::Def(DefKind::TyAlias, def_id) = path.res {
- // Substitute private type aliases
- if let Some(def_id) = def_id.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- if !cx.renderinfo.borrow().access_levels.is_exported(def_id.to_def_id()) {
- alias = Some(&cx.tcx.hir().expect_item(hir_id).kind);
- }
- }
- };
-
- if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias {
- let provided_params = &path.segments.last().expect("segments were empty");
- let mut ty_substs = FxHashMap::default();
- let mut lt_substs = FxHashMap::default();
- let mut ct_substs = FxHashMap::default();
- let generic_args = provided_params.generic_args();
- {
- let mut indices: GenericParamCount = Default::default();
- for param in generics.params.iter() {
- match param.kind {
- hir::GenericParamKind::Lifetime { .. } => {
- let mut j = 0;
- let lifetime =
- generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) => {
- if indices.lifetimes == j {
- return Some(lt);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(lt) = lifetime.cloned() {
- let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let cleaned = if !lt.is_elided() {
- lt.clean(cx)
- } else {
- self::types::Lifetime::elided()
- };
- lt_substs.insert(lt_def_id.to_def_id(), cleaned);
- }
- indices.lifetimes += 1;
- }
- hir::GenericParamKind::Type { ref default, .. } => {
- let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let type_ =
- generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Type(ty) => {
- if indices.types == j {
- return Some(ty);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ty) = type_ {
- ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx));
- } else if let Some(default) = *default {
- ty_substs
- .insert(ty_param_def_id.to_def_id(), default.clean(cx));
- }
- indices.types += 1;
- }
- hir::GenericParamKind::Const { .. } => {
- let const_param_def_id =
- cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let const_ =
- generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Const(ct) => {
- if indices.consts == j {
- return Some(ct);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ct) = const_ {
- ct_substs
- .insert(const_param_def_id.to_def_id(), ct.clean(cx));
- }
- // FIXME(const_generics:defaults)
- indices.consts += 1;
- }
- }
- }
- }
- return cx.enter_alias(ty_substs, lt_substs, ct_substs, || ty.clean(cx));
- }
- resolve_type(cx, path.clean(cx), self.hir_id)
- }
- TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref p)) => {
- let segments = if p.is_global() { &p.segments[1..] } else { &p.segments };
- let trait_segments = &segments[..segments.len() - 1];
- let trait_path = self::Path {
- global: p.is_global(),
- res: Res::Def(
- DefKind::Trait,
- cx.tcx.associated_item(p.res.def_id()).container.id(),
- ),
- segments: trait_segments.clean(cx),
- };
- Type::QPath {
- name: p.segments.last().expect("segments were empty").ident.name.clean(cx),
- self_type: box qself.clean(cx),
- trait_: box resolve_type(cx, trait_path, self.hir_id),
- }
- }
- TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
- let mut res = Res::Err;
- let ty = hir_ty_to_ty(cx.tcx, self);
- if let ty::Projection(proj) = ty.kind() {
- res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id);
- }
- let trait_path = hir::Path { span: self.span, res, segments: &[] };
- Type::QPath {
- name: segment.ident.name.clean(cx),
- self_type: box qself.clean(cx),
- trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id),
- }
- }
- TyKind::Path(hir::QPath::LangItem(..)) => {
- bug!("clean: requiring documentation of lang item")
- }
+ TyKind::Path(_) => clean_qpath(&self, cx),
TyKind::TraitObject(ref bounds, ref lifetime) => {
match bounds[0].clean(cx).trait_ {
ResolvedPath { path, param_names: None, did, is_generic } => {
}
}
+/// Returns `None` if the type could not be normalized
+#[allow(unreachable_code, unused_variables)]
+fn normalize(cx: &DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
+ return None; // HACK: low-churn fix for #79459 while we wait for a trait normalization fix
+ use crate::rustc_trait_selection::infer::TyCtxtInferExt;
+ use crate::rustc_trait_selection::traits::query::normalize::AtExt;
+ use rustc_middle::traits::ObligationCause;
+
+ // Try to normalize `<X as Y>::T` to a type
+ let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
+ let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
+ infcx
+ .at(&ObligationCause::dummy(), cx.param_env.get())
+ .normalize(lifted)
+ .map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
+ });
+ match normalized {
+ Ok(normalized_value) => {
+ debug!("normalized {:?} to {:?}", ty, normalized_value);
+ Some(normalized_value)
+ }
+ Err(err) => {
+ debug!("failed to normalize {:?}: {:?}", ty, err);
+ None
+ }
+ }
+}
+
impl<'tcx> Clean<Type> for Ty<'tcx> {
fn clean(&self, cx: &DocContext<'_>) -> Type {
debug!("cleaning type: {:?}", self);
- match *self.kind() {
+ let ty = normalize(cx, self).unwrap_or(self);
+ match *ty.kind() {
ty::Never => Never,
ty::Bool => Primitive(PrimitiveType::Bool),
ty::Char => Primitive(PrimitiveType::Char),
fn clean(&self, cx: &DocContext<'_>) -> Item {
let what_rustc_thinks = Item::from_def_id_and_parts(
self.did,
- Some(self.ident.name),
+ Some(self.ident.name.clean(cx)),
StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
cx,
);
}
}
-impl Clean<Item> for doctree::Struct<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- StructItem(Struct {
- struct_type: self.struct_type,
- generics: self.generics.clean(cx),
- fields: self.fields.clean(cx),
- fields_stripped: false,
- }),
- cx,
- )
- }
-}
-
-impl Clean<Item> for doctree::Union<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- UnionItem(Union {
- struct_type: self.struct_type,
- generics: self.generics.clean(cx),
- fields: self.fields.clean(cx),
- fields_stripped: false,
- }),
- cx,
- )
- }
-}
-
impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
VariantStruct {
}
}
-impl Clean<Item> for doctree::Enum<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- EnumItem(Enum {
- variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
- generics: self.generics.clean(cx),
- variants_stripped: false,
- }),
- cx,
- )
- }
-}
-
impl Clean<Item> for doctree::Variant<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let what_rustc_thinks = Item::from_hir_id_and_parts(
fields: self
.fields
.iter()
- .map(|field| Item {
- source: cx.tcx.def_span(field.did).clean(cx),
- name: Some(field.ident.name.clean(cx)),
- attrs: cx.tcx.get_attrs(field.did).clean(cx),
- visibility: Visibility::Inherited,
- def_id: field.did,
- stability: get_stability(cx, field.did),
- deprecation: get_deprecation(cx, field.did),
- kind: StructFieldItem(cx.tcx.type_of(field.did).clean(cx)),
+ .map(|field| {
+ let name = Some(field.ident.name.clean(cx));
+ let kind = StructFieldItem(cx.tcx.type_of(field.did).clean(cx));
+ let what_rustc_thinks =
+ Item::from_def_id_and_parts(field.did, name, kind, cx);
+ // don't show `pub` for fields, which are always public
+ Item { visibility: Visibility::Inherited, ..what_rustc_thinks }
})
.collect(),
}),
};
let what_rustc_thinks = Item::from_def_id_and_parts(
self.def_id,
- Some(self.ident.name),
+ Some(self.ident.name.clean(cx)),
VariantItem(Variant { kind }),
cx,
);
}
}
-impl Clean<Item> for doctree::Typedef<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- let type_ = self.ty.clean(cx);
- let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
- cx,
- )
- }
-}
-
-impl Clean<Item> for doctree::OpaqueTy<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- OpaqueTyItem(OpaqueTy {
- bounds: self.opaque_ty.bounds.clean(cx),
- generics: self.opaque_ty.generics.clean(cx),
- }),
- cx,
- )
- }
-}
-
impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, || {
}
}
-impl Clean<Item> for doctree::Static<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- StaticItem(Static {
- type_: self.type_.clean(cx),
- mutability: self.mutability,
- expr: print_const_expr(cx, self.expr),
- }),
- cx,
- )
+impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Ident>) {
+ fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
+ use hir::ItemKind;
+
+ let (item, renamed) = self;
+ let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id();
+ let mut name = match renamed {
+ Some(ident) => ident.name,
+ None => cx.tcx.hir().name(item.hir_id),
+ };
+ cx.with_param_env(def_id, || {
+ let kind = match item.kind {
+ ItemKind::Static(ty, mutability, body_id) => StaticItem(Static {
+ type_: ty.clean(cx),
+ mutability,
+ expr: print_const_expr(cx, body_id),
+ }),
+ ItemKind::Const(ty, body_id) => ConstantItem(Constant {
+ type_: ty.clean(cx),
+ expr: print_const_expr(cx, body_id),
+ value: print_evaluated_const(cx, def_id),
+ is_literal: is_literal_expr(cx, body_id.hir_id),
+ }),
+ ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
+ bounds: ty.bounds.clean(cx),
+ generics: ty.generics.clean(cx),
+ }),
+ ItemKind::TyAlias(ty, ref generics) => {
+ let rustdoc_ty = ty.clean(cx);
+ let item_type = rustdoc_ty.def_id().and_then(|did| inline::build_ty(cx, did));
+ TypedefItem(
+ Typedef { type_: rustdoc_ty, generics: generics.clean(cx), item_type },
+ false,
+ )
+ }
+ ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
+ variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
+ generics: generics.clean(cx),
+ variants_stripped: false,
+ }),
+ ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+ generics: generics.clean(cx),
+ bounds: bounds.clean(cx),
+ }),
+ ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
+ struct_type: doctree::struct_type_from_def(&variant_data),
+ generics: generics.clean(cx),
+ fields: variant_data.fields().clean(cx),
+ fields_stripped: false,
+ }),
+ ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
+ struct_type: doctree::struct_type_from_def(&variant_data),
+ generics: generics.clean(cx),
+ fields: variant_data.fields().clean(cx),
+ fields_stripped: false,
+ }),
+ ItemKind::Impl { .. } => return clean_impl(item, cx),
+ // proc macros can have a name set by attributes
+ ItemKind::Fn(ref sig, ref generics, body_id) => {
+ clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
+ }
+ hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
+ let items = item_ids
+ .iter()
+ .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
+ .collect();
+ let attrs = item.attrs.clean(cx);
+ let is_spotlight = attrs.has_doc_flag(sym::spotlight);
+ TraitItem(Trait {
+ unsafety,
+ items,
+ generics: generics.clean(cx),
+ bounds: bounds.clean(cx),
+ is_spotlight,
+ is_auto: is_auto.clean(cx),
+ })
+ }
+ ItemKind::ExternCrate(orig_name) => {
+ return clean_extern_crate(item, name, orig_name, cx);
+ }
+ _ => unreachable!("not yet converted"),
+ };
+
+ vec![Item::from_def_id_and_parts(def_id, Some(name.clean(cx)), kind, cx)]
+ })
}
}
-impl Clean<Item> for doctree::Constant<'_> {
+impl Clean<Item> for hir::Variant<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
- let def_id = cx.tcx.hir().local_def_id(self.id).to_def_id();
-
- Item::from_def_id_and_parts(
- def_id,
- Some(self.name),
- ConstantItem(Constant {
- type_: self.type_.clean(cx),
- expr: print_const_expr(cx, self.expr),
- value: print_evaluated_const(cx, def_id),
- is_literal: is_literal_expr(cx, self.expr.hir_id),
- }),
- cx,
- )
+ let kind = VariantItem(Variant { kind: self.data.clean(cx) });
+ let what_rustc_thinks =
+ Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
+ // don't show `pub` for variants, which are always public
+ Item { visibility: Inherited, ..what_rustc_thinks }
}
}
}
}
-impl Clean<Vec<Item>> for doctree::Impl<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
- let mut ret = Vec::new();
- let trait_ = self.trait_.clean(cx);
- let items = self.items.iter().map(|ii| ii.clean(cx)).collect::<Vec<_>>();
- let def_id = cx.tcx.hir().local_def_id(self.id);
-
- // If this impl block is an implementation of the Deref trait, then we
- // need to try inlining the target's inherent impl blocks as well.
- if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
- build_deref_target_impls(cx, &items, &mut ret);
+fn clean_impl(impl_: &hir::Item<'_>, cx: &DocContext<'_>) -> Vec<Item> {
+ let mut ret = Vec::new();
+ let (trait_, items, for_, unsafety, generics) = match &impl_.kind {
+ hir::ItemKind::Impl { of_trait, items, self_ty, unsafety, generics, .. } => {
+ (of_trait, items, self_ty, *unsafety, generics)
}
-
- let provided: FxHashSet<String> = trait_
- .def_id()
- .map(|did| {
- cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()
- })
- .unwrap_or_default();
-
- let for_ = self.for_.clean(cx);
- let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
- DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
- _ => None,
+ _ => unreachable!(),
+ };
+ let trait_ = trait_.clean(cx);
+ let items = items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+ let def_id = cx.tcx.hir().local_def_id(impl_.hir_id);
+
+ // If this impl block is an implementation of the Deref trait, then we
+ // need to try inlining the target's inherent impl blocks as well.
+ if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
+ build_deref_target_impls(cx, &items, &mut ret);
+ }
+
+ let provided: FxHashSet<String> = trait_
+ .def_id()
+ .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect())
+ .unwrap_or_default();
+
+ let for_ = for_.clean(cx);
+ let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
+ DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
+ _ => None,
+ });
+ let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| {
+ let kind = ImplItem(Impl {
+ unsafety,
+ generics: generics.clean(cx),
+ provided_trait_methods: provided.clone(),
+ trait_,
+ for_,
+ items,
+ polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
+ synthetic: false,
+ blanket_impl: None,
+ });
+ Item::from_hir_id_and_parts(impl_.hir_id, None, kind, cx)
+ };
+ if let Some(type_alias) = type_alias {
+ ret.push(make_item(trait_.clone(), type_alias, items.clone()));
+ }
+ ret.push(make_item(trait_, for_, items));
+ ret
+}
+
+fn clean_extern_crate(
+ krate: &hir::Item<'_>,
+ name: Symbol,
+ orig_name: Option<Symbol>,
+ cx: &DocContext<'_>,
+) -> Vec<Item> {
+ // this is the ID of the `extern crate` statement
+ let def_id = cx.tcx.hir().local_def_id(krate.hir_id);
+ let cnum = cx.tcx.extern_mod_stmt_cnum(def_id).unwrap_or(LOCAL_CRATE);
+ // this is the ID of the crate itself
+ let crate_def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let please_inline = krate.vis.node.is_pub()
+ && krate.attrs.iter().any(|a| {
+ a.has_name(sym::doc)
+ && match a.meta_item_list() {
+ Some(l) => attr::list_contains_name(&l, sym::inline),
+ None => false,
+ }
});
- let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| Item {
- name: None,
- attrs: self.attrs.clean(cx),
- source: self.span.clean(cx),
- def_id: def_id.to_def_id(),
- visibility: self.vis.clean(cx),
- stability: cx.stability(self.id),
- deprecation: cx.deprecation(self.id).clean(cx),
- kind: ImplItem(Impl {
- unsafety: self.unsafety,
- generics: self.generics.clean(cx),
- provided_trait_methods: provided.clone(),
- trait_,
- for_,
- items,
- polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
- synthetic: false,
- blanket_impl: None,
- }),
- };
- if let Some(type_alias) = type_alias {
- ret.push(make_item(trait_.clone(), type_alias, items.clone()));
- }
- ret.push(make_item(trait_, for_, items));
- ret
- }
-}
-
-impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
- fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
- let please_inline = self.vis.node.is_pub()
- && self.attrs.iter().any(|a| {
- a.has_name(sym::doc)
- && match a.meta_item_list() {
- Some(l) => attr::list_contains_name(&l, sym::inline),
- None => false,
- }
- });
- if please_inline {
- let mut visited = FxHashSet::default();
+ if please_inline {
+ let mut visited = FxHashSet::default();
- let res = Res::Def(DefKind::Mod, DefId { krate: self.cnum, index: CRATE_DEF_INDEX });
+ let res = Res::Def(DefKind::Mod, crate_def_id);
- if let Some(items) = inline::try_inline(
- cx,
- cx.tcx.parent_module(self.hir_id).to_def_id(),
- res,
- self.name,
- Some(self.attrs),
- &mut visited,
- ) {
- return items;
- }
+ if let Some(items) = inline::try_inline(
+ cx,
+ cx.tcx.parent_module(krate.hir_id).to_def_id(),
+ res,
+ name,
+ Some(krate.attrs),
+ &mut visited,
+ ) {
+ return items;
}
-
- vec![Item {
- name: None,
- attrs: self.attrs.clean(cx),
- source: self.span.clean(cx),
- def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
- visibility: self.vis.clean(cx),
- stability: None,
- deprecation: None,
- kind: ExternCrateItem(self.name.clean(cx), self.path.clone()),
- }]
}
+ let path = orig_name.map(|x| x.to_string());
+ // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
+ vec![Item {
+ name: None,
+ attrs: krate.attrs.clean(cx),
+ source: krate.span.clean(cx),
+ def_id: crate_def_id,
+ visibility: krate.vis.clean(cx),
+ stability: None,
+ deprecation: None,
+ kind: ExternCrateItem(name.clean(cx), path),
+ }]
}
impl Clean<Vec<Item>> for doctree::Import<'_> {
}
}
-impl Clean<Item> for doctree::ForeignItem<'_> {
+impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Ident>) {
fn clean(&self, cx: &DocContext<'_>) -> Item {
- let kind = match self.kind {
- hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
- let abi = cx.tcx.hir().get_foreign_abi(self.id);
- let (generics, decl) =
- enter_impl_trait(cx, || (generics.clean(cx), (&**decl, &names[..]).clean(cx)));
- let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
- ForeignFunctionItem(Function {
- decl,
- generics,
- header: hir::FnHeader {
- unsafety: hir::Unsafety::Unsafe,
- abi,
- constness: hir::Constness::NotConst,
- asyncness: hir::IsAsync::NotAsync,
- },
- all_types,
- ret_types,
- })
- }
- hir::ForeignItemKind::Static(ref ty, mutbl) => ForeignStaticItem(Static {
- type_: ty.clean(cx),
- mutability: *mutbl,
- expr: String::new(),
- }),
- hir::ForeignItemKind::Type => ForeignTypeItem,
- };
+ let (item, renamed) = self;
+ cx.with_param_env(cx.tcx.hir().local_def_id(item.hir_id).to_def_id(), || {
+ let kind = match item.kind {
+ hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
+ let abi = cx.tcx.hir().get_foreign_abi(item.hir_id);
+ let (generics, decl) = enter_impl_trait(cx, || {
+ (generics.clean(cx), (&**decl, &names[..]).clean(cx))
+ });
+ let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
+ ForeignFunctionItem(Function {
+ decl,
+ generics,
+ header: hir::FnHeader {
+ unsafety: hir::Unsafety::Unsafe,
+ abi,
+ constness: hir::Constness::NotConst,
+ asyncness: hir::IsAsync::NotAsync,
+ },
+ all_types,
+ ret_types,
+ })
+ }
+ hir::ForeignItemKind::Static(ref ty, mutability) => ForeignStaticItem(Static {
+ type_: ty.clean(cx),
+ mutability,
+ expr: String::new(),
+ }),
+ hir::ForeignItemKind::Type => ForeignTypeItem,
+ };
- Item::from_hir_id_and_parts(self.id, Some(self.name), kind, cx)
+ Item::from_hir_id_and_parts(
+ item.hir_id,
+ Some(renamed.unwrap_or(item.ident).name),
+ kind,
+ cx,
+ )
+ })
}
}
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item::from_def_id_and_parts(
self.def_id,
- Some(self.name),
+ Some(self.name.clean(cx)),
MacroItem(Macro {
source: format!(
"macro_rules! {} {{\n{}}}",
}
}
-impl Clean<Item> for doctree::ProcMacro {
- fn clean(&self, cx: &DocContext<'_>) -> Item {
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }),
- cx,
- )
- }
-}
-
impl Clean<Deprecation> for attr::Deprecation {
fn clean(&self, _: &DocContext<'_>) -> Deprecation {
Deprecation {
use crate::clean::external_path;
use crate::clean::inline;
use crate::clean::types::Type::{QPath, ResolvedPath};
+use crate::clean::Clean;
use crate::core::DocContext;
use crate::doctree;
use crate::formats::cache::cache;
crate src: FileName,
crate module: Option<Item>,
crate externs: Vec<(CrateNum, ExternalCrate)>,
- crate primitives: Vec<(DefId, PrimitiveType, Attributes)>,
+ crate primitives: Vec<(DefId, PrimitiveType)>,
// These are later on moved into `CACHEKEY`, leaving the map empty.
// Only here so that they can be filtered through the rustdoc passes.
crate external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
crate name: String,
crate src: FileName,
crate attrs: Attributes,
- crate primitives: Vec<(DefId, PrimitiveType, Attributes)>,
- crate keywords: Vec<(DefId, String, Attributes)>,
+ crate primitives: Vec<(DefId, PrimitiveType)>,
+ crate keywords: Vec<(DefId, String)>,
}
/// Anything with a source location and set of attributes and, optionally, a
kind: ItemKind,
cx: &DocContext<'_>,
) -> Item {
- Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
+ Item::from_def_id_and_parts(
+ cx.tcx.hir().local_def_id(hir_id).to_def_id(),
+ name.clean(cx),
+ kind,
+ cx,
+ )
}
pub fn from_def_id_and_parts(
def_id: DefId,
- name: Option<Symbol>,
+ name: Option<String>,
kind: ItemKind,
cx: &DocContext<'_>,
) -> Item {
- use super::Clean;
-
debug!("name={:?}, def_id={:?}", name, def_id);
// `span_if_local()` lies about functions and only gives the span of the function signature
Item {
def_id,
kind,
- name: name.clean(cx),
+ name,
source: source.clean(cx),
attrs: cx.tcx.get_attrs(def_id).clean(cx),
visibility: cx.tcx.visibility(def_id).clean(cx),
use crate::clean::auto_trait::AutoTraitFinder;
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
- inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg,
- GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemKind, Lifetime,
- MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Type, TypeBinding,
- TypeKind, Visibility, WherePredicate,
+ inline, Clean, Crate, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg, GenericArgs,
+ GenericBound, Generics, GetDefId, ImportSource, Item, ItemKind, Lifetime, MacroKind, Path,
+ PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, TypeKind,
+ WherePredicate,
};
use crate::core::DocContext;
use itertools::Itertools;
-use rustc_attr::Stability;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
ItemKind::ModuleItem(ref mut m) => m,
_ => unreachable!(),
};
- m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| Item {
- source: Span::empty(),
- name: Some(prim.to_url_str().to_string()),
- attrs: attrs.clone(),
- visibility: Visibility::Public,
- stability: get_stability(cx, def_id),
- deprecation: get_deprecation(cx, def_id),
- def_id,
- kind: ItemKind::PrimitiveItem(prim),
+ m.items.extend(primitives.iter().map(|&(def_id, prim)| {
+ Item::from_def_id_and_parts(
+ def_id,
+ Some(prim.to_url_str().to_owned()),
+ ItemKind::PrimitiveItem(prim),
+ cx,
+ )
}));
- m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| Item {
- source: Span::empty(),
- name: Some(kw.clone()),
- attrs,
- visibility: Visibility::Public,
- stability: get_stability(cx, def_id),
- deprecation: get_deprecation(cx, def_id),
- def_id,
- kind: ItemKind::KeywordItem(kw),
+ 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)
}));
}
}
}
-// extract the stability index for a node from tcx, if possible
-crate fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
- cx.tcx.lookup_stability(def_id).cloned()
-}
-
-crate fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
- cx.tcx.lookup_deprecation(def_id).clean(cx)
-}
-
fn external_generic_args(
cx: &DocContext<'_>,
trait_did: Option<DefId>,
-use rustc_attr as attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc};
use rustc_driver::abort_on_err;
use rustc_middle::hir::map::Map;
use rustc_middle::middle::cstore::CrateStore;
use rustc_middle::middle::privacy::AccessLevels;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_resolve as resolve;
use rustc_session::config::{self, CrateType, ErrorOutputType};
use rustc_session::lint;
use rustc_span::symbol::sym;
use rustc_span::DUMMY_SP;
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
use std::mem;
use std::rc::Rc;
crate struct DocContext<'tcx> {
crate tcx: TyCtxt<'tcx>,
crate resolver: Rc<RefCell<interface::BoxedResolver>>,
+ /// Used for normalization.
+ ///
+ /// Most of this logic is copied from rustc_lint::late.
+ crate param_env: Cell<ParamEnv<'tcx>>,
/// Later on moved into `CACHE_KEY`
crate renderinfo: RefCell<RenderInfo>,
/// Later on moved through `clean::Crate` into `CACHE_KEY`
&self.tcx.sess
}
+ crate fn with_param_env<T, F: FnOnce() -> T>(&self, def_id: DefId, f: F) -> T {
+ let old_param_env = self.param_env.replace(self.tcx.param_env(def_id));
+ let ret = f();
+ self.param_env.set(old_param_env);
+ ret
+ }
+
crate fn enter_resolver<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut resolve::Resolver<'_>) -> R,
def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
}
}
-
- crate fn stability(&self, id: HirId) -> Option<attr::Stability> {
- self.tcx
- .hir()
- .opt_local_def_id(id)
- .and_then(|def_id| self.tcx.lookup_stability(def_id.to_def_id()))
- .cloned()
- }
-
- crate fn deprecation(&self, id: HirId) -> Option<attr::Deprecation> {
- self.tcx
- .hir()
- .opt_local_def_id(id)
- .and_then(|def_id| self.tcx.lookup_deprecation(def_id.to_def_id()))
- }
}
/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
let mut ctxt = DocContext {
tcx,
resolver,
+ param_env: Cell::new(ParamEnv::empty()),
external_traits: Default::default(),
active_extern_traits: Default::default(),
renderinfo: RefCell::new(renderinfo),
let folder_name = filename
.to_string()
.chars()
- .map(|c| if c == '/' || c == '.' { '_' } else { c })
+ .map(|c| if c == '\\' || c == '/' || c == '.' { '_' } else { c })
.collect::<String>();
path.push(format!(
- "{name}_{line}_{number}",
- name = folder_name,
+ "{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.
.and_modify(|v| *v += 1)
.or_insert(0)
},
- line = line,
));
std::fs::create_dir_all(&path)
crate use self::StructType::*;
use rustc_ast as ast;
-use rustc_span::hygiene::MacroKind;
-use rustc_span::{self, Span, Symbol};
+use rustc_span::{self, symbol::Ident, Span, Symbol};
use rustc_hir as hir;
-use rustc_hir::def_id::CrateNum;
-use rustc_hir::HirId;
crate struct Module<'hir> {
crate name: Option<Symbol>,
crate attrs: &'hir [ast::Attribute],
crate where_outer: Span,
crate where_inner: Span,
- crate extern_crates: Vec<ExternCrate<'hir>>,
crate imports: Vec<Import<'hir>>,
- crate structs: Vec<Struct<'hir>>,
- crate unions: Vec<Union<'hir>>,
- crate enums: Vec<Enum<'hir>>,
- crate fns: Vec<Function<'hir>>,
crate mods: Vec<Module<'hir>>,
crate id: hir::HirId,
- crate typedefs: Vec<Typedef<'hir>>,
- crate opaque_tys: Vec<OpaqueTy<'hir>>,
- crate statics: Vec<Static<'hir>>,
- crate constants: Vec<Constant<'hir>>,
- crate traits: Vec<Trait<'hir>>,
- crate impls: Vec<Impl<'hir>>,
- crate foreigns: Vec<ForeignItem<'hir>>,
+ // (item, renamed)
+ crate items: Vec<(&'hir hir::Item<'hir>, Option<Ident>)>,
+ crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Ident>)>,
crate macros: Vec<Macro>,
- crate proc_macros: Vec<ProcMacro>,
- crate trait_aliases: Vec<TraitAlias<'hir>>,
crate is_crate: bool,
}
where_outer: rustc_span::DUMMY_SP,
where_inner: rustc_span::DUMMY_SP,
attrs,
- extern_crates: Vec::new(),
imports: Vec::new(),
- structs: Vec::new(),
- unions: Vec::new(),
- enums: Vec::new(),
- fns: Vec::new(),
mods: Vec::new(),
- typedefs: Vec::new(),
- opaque_tys: Vec::new(),
- statics: Vec::new(),
- constants: Vec::new(),
- traits: Vec::new(),
- impls: Vec::new(),
+ items: Vec::new(),
foreigns: Vec::new(),
macros: Vec::new(),
- proc_macros: Vec::new(),
- trait_aliases: Vec::new(),
is_crate: false,
}
}
Unit,
}
-crate struct Struct<'hir> {
- crate id: hir::HirId,
- crate struct_type: StructType,
- crate name: Symbol,
- crate generics: &'hir hir::Generics<'hir>,
- crate fields: &'hir [hir::StructField<'hir>],
-}
-
-crate struct Union<'hir> {
- crate id: hir::HirId,
- crate struct_type: StructType,
- crate name: Symbol,
- crate generics: &'hir hir::Generics<'hir>,
- crate fields: &'hir [hir::StructField<'hir>],
-}
-
-crate struct Enum<'hir> {
- crate variants: Vec<Variant<'hir>>,
- crate generics: &'hir hir::Generics<'hir>,
- crate id: hir::HirId,
- crate name: Symbol,
-}
-
crate struct Variant<'hir> {
crate name: Symbol,
crate id: hir::HirId,
crate def: &'hir hir::VariantData<'hir>,
}
-crate struct Function<'hir> {
- crate decl: &'hir hir::FnDecl<'hir>,
- crate id: hir::HirId,
- crate name: Symbol,
- crate header: hir::FnHeader,
- crate generics: &'hir hir::Generics<'hir>,
- crate body: hir::BodyId,
-}
-
-crate struct Typedef<'hir> {
- crate ty: &'hir hir::Ty<'hir>,
- crate gen: &'hir hir::Generics<'hir>,
- crate name: Symbol,
- crate id: hir::HirId,
-}
-
-crate struct OpaqueTy<'hir> {
- crate opaque_ty: &'hir hir::OpaqueTy<'hir>,
- crate name: Symbol,
- crate id: hir::HirId,
-}
-
-#[derive(Debug)]
-crate struct Static<'hir> {
- crate type_: &'hir hir::Ty<'hir>,
- crate mutability: hir::Mutability,
- crate expr: hir::BodyId,
- crate name: Symbol,
- crate attrs: &'hir [ast::Attribute],
- crate vis: &'hir hir::Visibility<'hir>,
- crate id: hir::HirId,
- crate span: Span,
-}
-
-crate struct Constant<'hir> {
- crate type_: &'hir hir::Ty<'hir>,
- crate expr: hir::BodyId,
- crate name: Symbol,
- crate id: hir::HirId,
-}
-
-crate struct Trait<'hir> {
- crate is_auto: hir::IsAuto,
- crate unsafety: hir::Unsafety,
- crate name: Symbol,
- crate items: Vec<&'hir hir::TraitItem<'hir>>,
- crate generics: &'hir hir::Generics<'hir>,
- crate bounds: &'hir [hir::GenericBound<'hir>],
- crate attrs: &'hir [ast::Attribute],
- crate id: hir::HirId,
-}
-
-crate struct TraitAlias<'hir> {
- crate name: Symbol,
- crate generics: &'hir hir::Generics<'hir>,
- crate bounds: &'hir [hir::GenericBound<'hir>],
- crate id: hir::HirId,
-}
-
-#[derive(Debug)]
-crate struct Impl<'hir> {
- crate unsafety: hir::Unsafety,
- crate polarity: hir::ImplPolarity,
- crate defaultness: hir::Defaultness,
- crate constness: hir::Constness,
- crate generics: &'hir hir::Generics<'hir>,
- crate trait_: &'hir Option<hir::TraitRef<'hir>>,
- crate for_: &'hir hir::Ty<'hir>,
- crate items: Vec<&'hir hir::ImplItem<'hir>>,
- crate attrs: &'hir [ast::Attribute],
- crate span: Span,
- crate vis: &'hir hir::Visibility<'hir>,
- crate id: hir::HirId,
-}
-
-crate struct ForeignItem<'hir> {
- crate id: hir::HirId,
- crate name: Symbol,
- crate kind: &'hir hir::ForeignItemKind<'hir>,
-}
-
// For Macro we store the DefId instead of the NodeId, since we also create
// these imported macro_rules (which only have a DUMMY_NODE_ID).
crate struct Macro {
crate imported_from: Option<Symbol>,
}
-crate struct ExternCrate<'hir> {
- crate name: Symbol,
- crate hir_id: HirId,
- crate cnum: CrateNum,
- crate path: Option<String>,
- crate vis: &'hir hir::Visibility<'hir>,
- crate attrs: &'hir [ast::Attribute],
- crate span: Span,
-}
-
#[derive(Debug)]
crate struct Import<'hir> {
crate name: Symbol,
crate span: Span,
}
-crate struct ProcMacro {
- crate name: Symbol,
- crate id: hir::HirId,
- crate kind: MacroKind,
- crate helpers: Vec<Symbol>,
-}
-
crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
match *vdata {
hir::VariantData::Struct(..) => Plain,
crate trait DocFolder: Sized {
fn fold_item(&mut self, item: Item) -> Option<Item> {
- self.fold_item_recur(item)
+ Some(self.fold_item_recur(item))
}
/// don't override!
}
/// don't override!
- fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
- let Item { attrs, name, source, visibility, def_id, kind, stability, deprecation } = item;
-
- let kind = match kind {
+ fn fold_item_recur(&mut self, mut item: Item) -> Item {
+ item.kind = match item.kind {
StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
- _ => self.fold_inner_recur(kind),
+ _ => self.fold_inner_recur(item.kind),
};
-
- Some(Item { attrs, name, source, kind, visibility, stability, deprecation, def_id })
+ item
}
fn fold_mod(&mut self, m: Module) -> Module {
// Favor linking to as local extern as possible, so iterate all crates in
// reverse topological order.
for &(_, ref e) in krate.externs.iter().rev() {
- for &(def_id, prim, _) in &e.primitives {
+ for &(def_id, prim) in &e.primitives {
cache.primitive_locations.insert(prim, def_id);
}
}
- for &(def_id, prim, _) in &krate.primitives {
+ for &(def_id, prim) in &krate.primitives {
cache.primitive_locations.insert(prim, def_id);
}
// Once we've recursively found all the generics, hoard off all the
// implementations elsewhere.
- let ret = self.fold_item_recur(item).and_then(|item| {
- if let clean::Item { kind: clean::ImplItem(_), .. } = 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());
+ let item = self.fold_item_recur(item);
+ let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = 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());
- 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 {
- self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
- }
- } else {
- let trait_did = impl_item.trait_did().expect("no trait did");
- self.orphan_trait_impls.push((trait_did, dids, impl_item));
}
- None
} else {
- Some(item)
+ 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 {
+ self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+ }
+ } else {
+ let trait_did = impl_item.trait_did().expect("no trait did");
+ self.orphan_trait_impls.push((trait_did, dids, impl_item));
}
- });
+ None
+ } else {
+ Some(item)
+ };
if pushed {
self.stack.pop().expect("stack already empty");
#[cfg(test)]
mod tests;
+/// Options for rendering Markdown in the main body of documentation.
pub(crate) fn opts() -> Options {
Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH
}
+/// A subset of [`opts()`] used for rendering summaries.
+pub(crate) fn summary_opts() -> Options {
+ Options::ENABLE_STRIKETHROUGH
+}
+
/// When `to_string` is called, this struct will emit the HTML corresponding to
/// the rendered version of the contained markdown string.
pub struct Markdown<'a>(
}
};
- let p = Parser::new_with_broken_link_callback(
- md,
- Options::ENABLE_STRIKETHROUGH,
- Some(&mut replacer),
- );
+ let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
let mut s = String::new();
let mut s = String::with_capacity(md.len() * 3 / 2);
- for event in Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH) {
+ for event in Parser::new_ext(md, summary_opts()) {
match &event {
Event::Text(text) => s.push_str(text),
Event::Code(code) => {
}
}
+fn write_srclink(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) {
+ if let Some(l) = cx.src_href(item, cache) {
+ write!(
+ buf,
+ "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
+ l, "goto source code"
+ )
+ }
+}
+
#[derive(Debug, Eq, PartialEq, Hash)]
struct ItemEntry {
url: String,
// this page, and this link will be auto-clicked. The `id` attribute is
// used to find the link to auto-click.
if cx.shared.include_sources && !item.is_primitive() {
- if let Some(l) = cx.src_href(item, cache) {
- write!(
- buf,
- "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
- l, "goto source code"
- );
- }
+ write_srclink(cx, item, buf, cache);
}
write!(buf, "</span>"); // out-of-band
write!(w, "{}<span class=\"loading-content\">Loading content...</span>", extra_content)
}
- fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) {
+ fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item, cache: &Cache) {
let name = m.name.as_ref().unwrap();
info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default());
let item_type = m.type_();
render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
write!(w, "</code>");
render_stability_since(w, m, t);
+ write_srclink(cx, m, w, cache);
write!(w, "</h3>");
document(w, cx, m, Some(t));
}
"Associated Types",
"<div class=\"methods\">",
);
- for t in &types {
- trait_item(w, cx, *t, it);
+ for t in types {
+ trait_item(w, cx, t, it, cache);
}
write_loading_content(w, "</div>");
}
"Associated Constants",
"<div class=\"methods\">",
);
- for t in &consts {
- trait_item(w, cx, *t, it);
+ for t in consts {
+ trait_item(w, cx, t, it, cache);
}
write_loading_content(w, "</div>");
}
"Required methods",
"<div class=\"methods\">",
);
- for m in &required {
- trait_item(w, cx, *m, it);
+ for m in required {
+ trait_item(w, cx, m, it, cache);
}
write_loading_content(w, "</div>");
}
"Provided methods",
"<div class=\"methods\">",
);
- for m in &provided {
- trait_item(w, cx, *m, it);
+ for m in provided {
+ trait_item(w, cx, m, it, cache);
}
write_loading_content(w, "</div>");
}
StabilityLevel::Unstable { .. } => None,
});
render_stability_since_raw(w, since.as_deref(), outer_version);
- if let Some(l) = cx.src_href(&i.impl_item, cache) {
- write!(
- w,
- "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
- l, "goto source code"
- );
- }
+ write_srclink(cx, &i.impl_item, w, cache);
write!(w, "</h3>");
if trait_.is_some() {
render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
write!(w, "</code>");
render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
- if let Some(l) = cx.src_href(item, cache) {
- write!(
- w,
- "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
- l, "goto source code"
- );
- }
+ write_srclink(cx, item, w, cache);
write!(w, "</h4>");
}
}
assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "");
write!(w, "</code>");
render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
- if let Some(l) = cx.src_href(item, cache) {
- write!(
- w,
- "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
- l, "goto source code"
- );
- }
+ write_srclink(cx, item, w, cache);
write!(w, "</h4>");
}
clean::AssocTypeItem(ref bounds, ref default) => {
}
};
}
- self.fold_item_recur(item)
+ Some(self.fold_item_recur(item))
}
}
var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main";
if (action === "show") {
removeClass(relatedDoc, "fns-now-collapsed");
- removeClass(docblock, "hidden-by-usual-hider");
+ // Stability information is never hidden.
+ if (hasClass(docblock, "stability") === false) {
+ removeClass(docblock, "hidden-by-usual-hider");
+ }
onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule));
onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule));
} else if (action === "hide") {
addClass(relatedDoc, "fns-now-collapsed");
- addClass(docblock, "hidden-by-usual-hider");
+ // Stability information should be shown even when detailed info is hidden.
+ if (hasClass(docblock, "stability") === false) {
+ addClass(docblock, "hidden-by-usual-hider");
+ }
onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule));
onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule));
}
text-decoration: underline;
}
-.invisible > .srclink, h4 > code + .srclink {
+.invisible > .srclink, h4 > code + .srclink, h3 > code + .srclink {
position: absolute;
top: 0;
right: 0;
top: 0;
}
-.impl-items .since, .impl .since {
+.impl-items .since, .impl .since, .methods .since {
flex-grow: 0;
padding-left: 12px;
padding-right: 2px;
position: initial;
}
-.impl-items .srclink, .impl .srclink {
+.impl-items .srclink, .impl .srclink, .methods .srclink {
flex-grow: 0;
/* Override header settings otherwise it's too bold */
font-size: 17px;
font-weight: normal;
}
-.impl-items code, .impl code {
+.impl-items code, .impl code, .methods code {
flex-grow: 1;
}
-.impl-items h4, h4.impl, h3.impl {
+.impl-items h4, h4.impl, h3.impl, .methods h3 {
display: flex;
flex-basis: 100%;
font-size: 16px;
}
// need to move these items separately because we lose them by the time the closure is called,
- // but we can't crates the Handler ahead of time because it's not Send
+ // but we can't create the Handler ahead of time because it's not Send
let diag_opts = (options.error_format, options.edition, options.debugging_opts.clone());
let show_coverage = options.show_coverage;
let run_check = options.run_check;
}
}
- self.fold_item_recur(i)
+ Some(self.fold_item_recur(i))
}
}
}
}
- self.fold_item_recur(item)
+ Some(self.fold_item_recur(item))
}
}
impl fold::DocFolder for Collapser {
fn fold_item(&mut self, mut i: Item) -> Option<Item> {
i.attrs.collapse_doc_comments();
- self.fold_item_recur(i)
+ Some(self.fold_item_recur(i))
}
}
Res::PrimTy(prim) => Some(
self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
),
- Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => {
+ Res::Def(
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::TyAlias
+ | DefKind::ForeignTy,
+ did,
+ ) => {
debug!("looking for associated item named {} for item {:?}", item_name, did);
// Checks if item_name belongs to `impl SomeItem`
let assoc_item = cx
// we don't display docs on `extern crate` items anyway, so don't process them.
clean::ExternCrateItem(..) => {
debug!("ignoring extern crate item {:?}", item.def_id);
- return self.fold_item_recur(item);
+ return Some(self.fold_item_recur(item));
}
clean::ImportItem(Import { kind: clean::ImportKind::Simple(ref name, ..), .. }) => {
Some(name.clone())
}
}
- if item.is_mod() {
+ Some(if item.is_mod() {
if !item.attrs.inner_docs {
self.mod_ids.push(item.def_id);
}
ret
} else {
self.fold_item_recur(item)
- }
+ })
}
}
(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;
}
}
}
- self.fold_item_recur(i)
+ Some(self.fold_item_recur(i))
}
}
fn fold_item(&mut self, i: Item) -> Option<Item> {
self.items.insert(i.def_id);
- self.fold_item_recur(i)
+ Some(self.fold_item_recur(i))
}
}
look_for_tests(&cx, &dox, &item);
- self.fold_item_recur(item)
+ Some(self.fold_item_recur(item))
}
}
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- return self.fold_item_recur(item);
+ return Some(self.fold_item_recur(item));
}
};
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
}
}
- self.fold_item_recur(item)
+ Some(self.fold_item_recur(item))
}
}
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- return self.fold_item_recur(item);
+ return Some(self.fold_item_recur(item));
}
};
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
}
}
- self.fold_item_recur(item)
+ Some(self.fold_item_recur(item))
}
}
let result = self.fold_item_recur(item);
self.parent_cfg = old_parent_cfg;
- result
+ Some(result)
}
}
// strip things like impl methods but when doing so
// we must not add any items to the `retained` set.
let old = mem::replace(&mut self.update_retained, false);
- let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
+ let ret = StripItem(self.fold_item_recur(i)).strip();
self.update_retained = old;
return ret;
}
self.retained.insert(i.def_id);
}
}
- self.fold_item_recur(i)
+ Some(self.fold_item_recur(i))
}
}
let old = mem::replace(&mut self.update_retained, false);
let ret = self.fold_item_recur(i);
self.update_retained = old;
- return ret;
+ return Some(ret);
}
// These items can all get re-exported
clean::OpaqueTyItem(..)
if i.def_id.is_local() && !i.visibility.is_public() {
debug!("Stripper: stripping module {:?}", i.name);
let old = mem::replace(&mut self.update_retained, false);
- let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
+ let ret = StripItem(self.fold_item_recur(i)).strip();
self.update_retained = old;
return ret;
}
self.fold_item_recur(i)
};
- if let Some(ref i) = i {
- if self.update_retained {
- self.retained.insert(i.def_id);
- }
+ if self.update_retained {
+ self.retained.insert(i.def_id);
}
- i
+ Some(i)
}
}
}
}
}
- self.fold_item_recur(i)
+ Some(self.fold_item_recur(i))
}
}
fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.kind {
clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None,
- _ => self.fold_item_recur(i),
+ _ => Some(self.fold_item_recur(i)),
}
}
}
impl fold::DocFolder for CommentCleaner {
fn fold_item(&mut self, mut i: Item) -> Option<Item> {
i.attrs.unindent_doc_comments();
- self.fold_item_recur(i)
+ Some(self.fold_item_recur(i))
}
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::DefId;
use rustc_hir::Node;
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
-use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, Span};
module
}
- fn visit_variant_data(
- &mut self,
- item: &'tcx hir::Item<'_>,
- name: Symbol,
- sd: &'tcx hir::VariantData<'_>,
- generics: &'tcx hir::Generics<'_>,
- ) -> Struct<'tcx> {
- debug!("visiting struct");
- let struct_type = struct_type_from_def(&*sd);
- Struct { id: item.hir_id, struct_type, name, generics, fields: sd.fields() }
- }
-
- fn visit_union_data(
- &mut self,
- item: &'tcx hir::Item<'_>,
- name: Symbol,
- sd: &'tcx hir::VariantData<'_>,
- generics: &'tcx hir::Generics<'_>,
- ) -> Union<'tcx> {
- debug!("visiting union");
- let struct_type = struct_type_from_def(&*sd);
- Union { id: item.hir_id, struct_type, name, generics, fields: sd.fields() }
- }
-
- fn visit_enum_def(
- &mut self,
- it: &'tcx hir::Item<'_>,
- name: Symbol,
- def: &'tcx hir::EnumDef<'_>,
- generics: &'tcx hir::Generics<'_>,
- ) -> Enum<'tcx> {
- debug!("visiting enum");
- Enum {
- name,
- variants: def
- .variants
- .iter()
- .map(|v| Variant { name: v.ident.name, id: v.id, def: &v.data })
- .collect(),
- generics,
- id: it.hir_id,
- }
- }
-
- fn visit_fn(
- &mut self,
- om: &mut Module<'tcx>,
- item: &'tcx hir::Item<'_>,
- name: Symbol,
- decl: &'tcx hir::FnDecl<'_>,
- header: hir::FnHeader,
- generics: &'tcx hir::Generics<'_>,
- body: hir::BodyId,
- ) {
- debug!("visiting fn");
- let macro_kind = item.attrs.iter().find_map(|a| {
- if a.has_name(sym::proc_macro) {
- Some(MacroKind::Bang)
- } else if a.has_name(sym::proc_macro_derive) {
- Some(MacroKind::Derive)
- } else if a.has_name(sym::proc_macro_attribute) {
- Some(MacroKind::Attr)
- } else {
- None
- }
- });
- match macro_kind {
- Some(kind) => {
- let name = if kind == MacroKind::Derive {
- item.attrs
- .lists(sym::proc_macro_derive)
- .find_map(|mi| mi.ident())
- .expect("proc-macro derives require a name")
- .name
- } else {
- name
- };
-
- let mut helpers = Vec::new();
- for mi in item.attrs.lists(sym::proc_macro_derive) {
- if !mi.has_name(sym::attributes) {
- continue;
- }
-
- if let Some(list) = mi.meta_item_list() {
- for inner_mi in list {
- if let Some(ident) = inner_mi.ident() {
- helpers.push(ident.name);
- }
- }
- }
- }
-
- om.proc_macros.push(ProcMacro { name, id: item.hir_id, kind, helpers });
- }
- None => {
- om.fns.push(Function { id: item.hir_id, decl, name, generics, header, body });
- }
- }
- }
-
fn visit_mod_contents(
&mut self,
span: Span,
}
match item.kind {
- hir::ItemKind::ForeignMod(ref fm) => {
- for item in fm.items {
+ hir::ItemKind::ForeignMod { items, .. } => {
+ for item in items {
+ let item = self.cx.tcx.hir().foreign_item(item.id);
self.visit_foreign_item(item, None, om);
}
}
// If we're inlining, skip private items.
_ if self.inlining && !item.vis.node.is_pub() => {}
hir::ItemKind::GlobalAsm(..) => {}
- hir::ItemKind::ExternCrate(orig_name) => {
- let def_id = self.cx.tcx.hir().local_def_id(item.hir_id);
- om.extern_crates.push(ExternCrate {
- cnum: self.cx.tcx.extern_mod_stmt_cnum(def_id).unwrap_or(LOCAL_CRATE),
- name: ident.name,
- hir_id: item.hir_id,
- path: orig_name.map(|x| x.to_string()),
- vis: &item.vis,
- attrs: &item.attrs,
- span: item.span,
- })
- }
hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
hir::ItemKind::Use(ref path, kind) => {
let is_glob = kind == hir::UseKind::Glob;
Some(ident.name),
));
}
- hir::ItemKind::Enum(ref ed, ref gen) => {
- om.enums.push(self.visit_enum_def(item, ident.name, ed, gen))
- }
- hir::ItemKind::Struct(ref sd, ref gen) => {
- om.structs.push(self.visit_variant_data(item, ident.name, sd, gen))
- }
- hir::ItemKind::Union(ref sd, ref gen) => {
- om.unions.push(self.visit_union_data(item, ident.name, sd, gen))
- }
- hir::ItemKind::Fn(ref sig, ref gen, body) => {
- self.visit_fn(om, item, ident.name, &sig.decl, sig.header, gen, body)
- }
- hir::ItemKind::TyAlias(ty, ref gen) => {
- let t = Typedef { ty, gen, name: ident.name, id: item.hir_id };
- om.typedefs.push(t);
- }
- hir::ItemKind::OpaqueTy(ref opaque_ty) => {
- let t = OpaqueTy { opaque_ty, name: ident.name, id: item.hir_id };
- om.opaque_tys.push(t);
- }
- hir::ItemKind::Static(type_, mutability, expr) => {
- let s = Static {
- type_,
- mutability,
- expr,
- id: item.hir_id,
- name: ident.name,
- attrs: &item.attrs,
- span: item.span,
- vis: &item.vis,
- };
- om.statics.push(s);
- }
- hir::ItemKind::Const(type_, expr) => {
+ hir::ItemKind::Fn(..)
+ | hir::ItemKind::ExternCrate(..)
+ | hir::ItemKind::Enum(..)
+ | hir::ItemKind::Struct(..)
+ | hir::ItemKind::Union(..)
+ | hir::ItemKind::TyAlias(..)
+ | hir::ItemKind::OpaqueTy(..)
+ | hir::ItemKind::Static(..)
+ | hir::ItemKind::Trait(..)
+ | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
+ hir::ItemKind::Const(..) => {
// Underscore constants do not correspond to a nameable item and
// so are never useful in documentation.
if ident.name != kw::Underscore {
- let s = Constant { type_, expr, id: item.hir_id, name: ident.name };
- om.constants.push(s);
+ om.items.push((item, renamed));
}
}
- hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
- let items = item_ids.iter().map(|ti| self.cx.tcx.hir().trait_item(ti.id)).collect();
- let t = Trait {
- is_auto,
- unsafety,
- name: ident.name,
- items,
- generics,
- bounds,
- id: item.hir_id,
- attrs: &item.attrs,
- };
- om.traits.push(t);
- }
- hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
- let t = TraitAlias { name: ident.name, generics, bounds, id: item.hir_id };
- om.trait_aliases.push(t);
- }
-
- hir::ItemKind::Impl {
- unsafety,
- polarity,
- defaultness,
- constness,
- defaultness_span: _,
- ref generics,
- ref of_trait,
- self_ty,
- ref items,
- } => {
+ hir::ItemKind::Impl { ref of_trait, .. } => {
// Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
// them up regardless of where they're located.
if !self.inlining && of_trait.is_none() {
- let items =
- items.iter().map(|item| self.cx.tcx.hir().impl_item(item.id)).collect();
- let i = Impl {
- unsafety,
- polarity,
- defaultness,
- constness,
- generics,
- trait_: of_trait,
- for_: self_ty,
- items,
- attrs: &item.attrs,
- id: item.hir_id,
- span: item.span,
- vis: &item.vis,
- };
- om.impls.push(i);
+ om.items.push((item, None));
}
}
}
om: &mut Module<'tcx>,
) {
// If inlining we only want to include public functions.
- if self.inlining && !item.vis.node.is_pub() {
- return;
+ if !self.inlining || item.vis.node.is_pub() {
+ om.foreigns.push((item, renamed));
}
-
- om.foreigns.push(ForeignItem {
- id: item.hir_id,
- name: renamed.unwrap_or(item.ident).name,
- kind: &item.kind,
- });
}
// Convert each `exported_macro` into a doc item.
# stable release's version number. `date` is the date where the release we're
# bootstrapping off was released.
-date: 2020-10-16
+date: 2020-11-18
rustc: beta
# We use a nightly rustfmt to format the source because it solves some
# bootstrapping issues with use of new syntax in this repo. If you're looking at
# the beta/stable branch, this key should be omitted, as we don't want to depend
# on rustfmt from nightly there.
-rustfmt: nightly-2020-10-12
+rustfmt: nightly-2020-11-19
# When making a stable release the process currently looks like:
#
// This test is for *-windows-msvc only.
// ignore-android
-// ignore-cloudabi
// ignore-dragonfly
// ignore-emscripten
// ignore-freebsd
--- /dev/null
+// no-system-llvm
+// compile-flags: -Coverflow-checks=no -O
+// revisions: YES NO
+// [YES]compile-flags: -Zfewer-names=yes
+// [NO] compile-flags: -Zfewer-names=no
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn sum(x: u32, y: u32) -> u32 {
+// YES-LABEL: define i32 @sum(i32 %0, i32 %1)
+// YES-NEXT: %3 = add i32 %1, %0
+// YES-NEXT: ret i32 %3
+
+// NO-LABEL: define i32 @sum(i32 %x, i32 %y)
+// NO-NEXT: start:
+// NO-NEXT: %z = add i32 %y, %x
+// NO-NEXT: ret i32 %z
+ let z = x + y;
+ z
+}
-// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0
+// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
#![feature(naked_functions)]
// CHECK: Function Attrs: naked
#[no_mangle]
#[naked]
-// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+( %0)?}})
+// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+( %a)?}})
pub fn naked_with_args(a: isize) {
// CHECK-NEXT: {{.+}}:
- // CHECK-NEXT: %a = alloca i{{[0-9]+}}
- &a; // keep variable in an alloca
// CHECK: ret void
}
}
// CHECK: Function Attrs: naked
-// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+( %0)?}})
+// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+( %a)?}})
#[no_mangle]
#[naked]
pub fn naked_with_args_and_return(a: isize) -> isize {
// CHECK-NEXT: {{.+}}:
- // CHECK-NEXT: %a = alloca i{{[0-9]+}}
- &a; // keep variable in an alloca
- // CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
- a
-}
-
-// CHECK: Function Attrs: naked
-// CHECK-NEXT: define void @naked_recursive()
-#[no_mangle]
-#[naked]
-pub fn naked_recursive() {
- // CHECK-NEXT: {{.+}}:
- // CHECK-NEXT: call void @naked_empty()
-
- // FIXME(#39685) Avoid one block per call.
- // CHECK-NEXT: br label %bb1
- // CHECK: bb1:
-
- naked_empty();
-
- // CHECK-NEXT: %_4 = call i{{[0-9]+}} @naked_with_return()
-
- // FIXME(#39685) Avoid one block per call.
- // CHECK-NEXT: br label %bb2
- // CHECK: bb2:
-
- // CHECK-NEXT: %_3 = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %_4)
-
- // FIXME(#39685) Avoid one block per call.
- // CHECK-NEXT: br label %bb3
- // CHECK: bb3:
-
- // CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %_3)
-
- // FIXME(#39685) Avoid one block per call.
- // CHECK-NEXT: br label %bb4
- // CHECK: bb4:
-
- naked_with_args(
- naked_with_args_and_return(
- naked_with_return()
- )
- );
- // CHECK-NEXT: ret void
+ // CHECK: ret i{{[0-9]+}} 0
+ 0
}
--- /dev/null
+// Checks that naked functions are never inlined.
+// compile-flags: -O -Zmir-opt-level=2
+// ignore-wasm32
+#![crate_type = "lib"]
+#![feature(asm)]
+#![feature(naked_functions)]
+
+#[inline(always)]
+#[naked]
+#[no_mangle]
+pub unsafe extern "C" fn f() {
+// Check that f has naked and noinline attributes.
+//
+// CHECK: define void @f() unnamed_addr [[ATTR:#[0-9]+]]
+// CHECK-NEXT: start:
+// CHECK-NEXT: call void asm
+ asm!("", options(noreturn));
+}
+
+#[no_mangle]
+pub unsafe fn g() {
+// Check that call to f is not inlined.
+//
+// CHECK-LABEL: define void @g()
+// CHECK-NEXT: start:
+// CHECK-NEXT: call void @f()
+ f();
+}
+
+// CHECK: attributes [[ATTR]] = { naked noinline{{.*}} }
// This test is for *-windows-msvc only.
// ignore-android
-// ignore-cloudabi
// ignore-dragonfly
// ignore-emscripten
// ignore-freebsd
--- /dev/null
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @copy_to_vec
+#[no_mangle]
+fn copy_to_vec(s: &[u64]) -> Vec<u64> {
+ s.to_vec()
+ // CHECK: call void @llvm.memcpy
+}
// ignore-windows failing on win32 bot
// ignore-freebsd: gdb package too new
// ignore-android: FIXME(#10381)
+// ignore-macos: FIXME(#78665)
// compile-flags:-g
// The pretty printers being tested here require the patch from
btree_set.insert(i);
}
- let mut empty_btree_set: BTreeSet<i32> = BTreeSet::new();
+ let empty_btree_set: BTreeSet<i32> = BTreeSet::new();
// BTreeMap
let mut btree_map = BTreeMap::new();
btree_map.insert(i, i);
}
- let mut empty_btree_map: BTreeMap<i32, u32> = BTreeMap::new();
+ let empty_btree_map: BTreeMap<i32, u32> = BTreeMap::new();
let mut option_btree_map: BTreeMap<bool, Option<bool>> = BTreeMap::new();
option_btree_map.insert(false, None);
// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}
// gdb-command: print vec
-// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}
+// gdb-check:$2 = Vec<u64, alloc::alloc::Global>(len: 4, cap: [...]) = {4, 5, 6, 7}
// gdb-command: print str_slice
// gdb-check:$3 = "IAMA string slice!"
// 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>]
+// cdb-check:vec,d [...] : { size=4 } [Type: [...]::Vec<u64, alloc::alloc::Global>]
// cdb-check: [size] : 4 [Type: [...]]
// cdb-check: [capacity] : [...] [Type: [...]]
// cdb-check: [0] : 4 [Type: unsigned __int64]
// revisions:cfail1 cfail2
// compile-flags: -Z query-dep-graph
// aux-build:point.rs
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
// revisions:cfail1 cfail2
// compile-flags: -Z query-dep-graph
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
// revisions:cfail1 cfail2
// compile-flags: -Z query-dep-graph
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
// revisions:cfail1 cfail2
// compile-flags: -Z query-dep-graph
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
#![crate_type = "rlib"]
#![feature(rustc_attrs)]
// revisions:cfail1 cfail2
// compile-flags: -Z query-dep-graph
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
#![crate_type = "rlib"]
#![feature(rustc_attrs)]
#![feature(rustc_attrs)]
#![feature(unboxed_closures)]
#![feature(link_args)]
-#![crate_type="rlib"]
-
+#![crate_type = "rlib"]
// Change function name --------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn change_function_name1(c: i64) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn change_function_name2(c: i64) -> i32;
}
-
-
// Change parameter name -------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn change_parameter_name(c: i64) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn change_parameter_name(d: i64) -> i32;
}
-
-
// Change parameter type -------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn change_parameter_type(c: i64) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn change_parameter_type(c: i32) -> i32;
}
-
-
// Change return type ----------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn change_return_type(c: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn change_return_type(c: i32) -> i8;
}
-
-
// Add parameter ---------------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn add_parameter(c: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn add_parameter(c: i32, d: i32) -> i32;
}
-
-
// Add return type -------------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn add_return_type(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn add_return_type(c: i32) -> i32;
}
-
-
// Make function variadic ------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn make_function_variadic(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn make_function_variadic(c: i32, ...);
}
-
-
// Change calling convention ---------------------------------------------------
#[cfg(cfail1)]
extern "C" {
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
extern "rust-call" {
pub fn change_calling_convention(c: i32);
}
-
-
// Make function public --------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
fn make_function_public(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn make_function_public(c: i32);
}
-
-
// Add function ----------------------------------------------------------------
#[cfg(cfail1)]
-extern {
+extern "C" {
pub fn add_function1(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
-extern {
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
+extern "C" {
pub fn add_function1(c: i32);
pub fn add_function2();
}
-
-
// Change link-args ------------------------------------------------------------
#[cfg(cfail1)]
#[link_args = "-foo -bar"]
-extern {
+extern "C" {
pub fn change_link_args(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
#[link_args = "-foo -bar -baz"]
-extern {
+extern "C" {
pub fn change_link_args(c: i32);
}
-
-
// Change link-name ------------------------------------------------------------
#[cfg(cfail1)]
#[link(name = "foo")]
-extern {
+extern "C" {
pub fn change_link_name(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
-#[rustc_clean(cfg="cfail3")]
+#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail3")]
#[link(name = "bar")]
-extern {
+extern "C" {
pub fn change_link_name(c: i32);
}
#[cfg(not(cfail1))]
use super::c_i64 as c_int;
- #[rustc_dirty(cfg="cfail2")]
- #[rustc_clean(cfg="cfail3")]
- extern {
+ #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg = "cfail3")]
+ extern "C" {
pub fn indirectly_change_parameter_type(c: c_int);
}
}
-
-
// Indirectly change return type --------------------------------------------
mod indirectly_change_return_type {
#[cfg(cfail1)]
#[cfg(not(cfail1))]
use super::c_i64 as c_int;
- #[rustc_dirty(cfg="cfail2")]
- #[rustc_clean(cfg="cfail3")]
- extern {
+ #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg = "cfail3")]
+ extern "C" {
pub fn indirectly_change_return_type() -> c_int;
}
}
// revisions:cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph --test
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
#![feature(rustc_attrs)]
#![crate_type = "rlib"]
let mut _8: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
let mut _9: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:21
let mut _10: i32; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:15
- let mut _11: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _11: !; // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
scope 1 {
debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10
let _2: i32; // in scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10
}
bb2: {
- StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic::<&str>(const "assertion failed: *y == 99"); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_11); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
+ core::panicking::panic(const "assertion failed: *y == 99"); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
- // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar(<ZST>)) }
+ // + span: $DIR/inst_combine_deref.rs:60:5: 60:23
+ // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
// ty::Const
// + ty: &str
// + val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 })
let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _14: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _16: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _17: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _22: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _12: std::fmt::Arguments; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _13: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _14: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _15: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _16: (&&i32, &&i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _17: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _18: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _19: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _20: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 5 {
- debug arg0 => _25; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug arg1 => _28; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _25; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _24; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug arg0 => _24; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug arg1 => _27; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _24; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _23; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _23: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _24: &&i32; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 7 {
}
}
- scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _28; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _27; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _27; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _26; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _25: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _26: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _27: &&i32; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 9 {
}
}
}
- scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug pieces => _29; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug args => _31; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug pieces => (_12.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug args => _29; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _28: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _29: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
}
}
}
bb2: {
- StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _14 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &[&str; 3]
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
- _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_12.0: &[&str]) = move _13 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _17 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_16.0: &&i32) = &_17; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_17.0: &&i32) = &_18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _20 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_17.1: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _25 = (_17.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _28 = (_17.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _19 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _18 = &_19; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_16.1: &&i32) = move _18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _24 = (_16.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _27 = (_16.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _23 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_23); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _23 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_22); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _22 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _23) -> bb3; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb3: {
- (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_20.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb4; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb4: {
- (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_23); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _27 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _22; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_22); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _26 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_26); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _26 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_25); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _25 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _26) -> bb5; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb5: {
- (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _27) -> bb6; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb6: {
- (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_26); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _16 = [move _21, move _22]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _15 = &_16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_30); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- discriminant(_30) = 0; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_30); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _25; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_25); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _15 = [move _20, move _21]; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _29 = move _14 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_28); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_28) = 0; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_12.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _28; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_12.2: &[std::fmt::ArgumentV1]) = move _29; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_28); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ core::panicking::panic_fmt(move _12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
- // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'r> fn(std::fmt::Arguments<'r>) -> ! {core::panicking::panic_fmt}, val: Value(Scalar(<ZST>)) }
}
}
let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _14: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _16: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _17: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _22: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _12: std::fmt::Arguments; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _13: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _14: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _15: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _16: (&&i32, &&i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _17: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _18: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _19: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _20: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 5 {
- debug arg0 => _25; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug arg1 => _28; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _25; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _24; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug arg0 => _24; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug arg1 => _27; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _24; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _23; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _23: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _24: &&i32; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 7 {
}
}
- scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _28; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _27; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _27; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _26; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _25: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _26: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _27: &&i32; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 9 {
}
}
}
- scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug pieces => _29; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug args => _31; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug pieces => (_12.0: &[&str]); // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug args => _29; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _28: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _29: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
}
}
}
bb2: {
- StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _14 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &[&str; 3]
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
- _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_12.0: &[&str]) = move _13 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _17 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_16.0: &&i32) = &_17; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_17.0: &&i32) = &_18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _20 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_17.1: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _25 = (_17.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _28 = (_17.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _19 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _18 = &_19; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_16.1: &&i32) = move _18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _24 = (_16.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _27 = (_16.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _23 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_23); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _23 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_22); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _22 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _23) -> bb3; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb3: {
- (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_20.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb4; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb4: {
- (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_23); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _27 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _22; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_22); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _26 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_26); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _26 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_25); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _25 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _26) -> bb5; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb5: {
- (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _27) -> bb6; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb6: {
- (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_26); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _16 = [move _21, move _22]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _15 = &_16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_30); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- discriminant(_30) = 0; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_30); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _25; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_25); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _15 = [move _20, move _21]; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _14 = &_15; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _29 = move _14 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_28); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_28) = 0; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_12.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _28; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_12.2: &[std::fmt::ArgumentV1]) = move _29; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_28); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ core::panicking::panic_fmt(move _12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
- // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'r> fn(std::fmt::Arguments<'r>) -> ! {core::panicking::panic_fmt}, val: Value(Scalar(<ZST>)) }
}
}
let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _18: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _20: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _21: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _22: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _23: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _24: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _25: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _26: [&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _27: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _28: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _29: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _30: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _31: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _20: std::fmt::Arguments; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _21: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _23: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _24: [&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _25: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _26: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _27: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _28: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _29: (&&i32, &&i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _30: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _31: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _32: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let _33: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _34: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _35: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _38: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _39: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _40: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _41: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _42: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _43: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _36: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _37: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _38: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _39: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _40: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _41: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _45: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _43: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 4 {
debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
debug right_val => _14; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _36: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _37: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _44: &[&str; 3]; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _34: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _35: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _42: &[&str; 3]; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 5 {
- debug arg0 => _36; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug arg1 => _37; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _39; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _40; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _46: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _47: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _48: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _49: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug arg0 => _34; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug arg1 => _35; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _37; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _38; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _44: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _45: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _46: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _47: &&i32; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 7 {
}
}
- scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _42; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _43; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _50: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _51: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _52: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _53: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _40; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _41; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _48: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _49: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _50: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _51: &&i32; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 9 {
}
}
}
- scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug pieces => _23; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug args => _27; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _54: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _55: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _56: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug pieces => _21; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug args => _25; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _52: &[&str]; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _53: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _54: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
}
}
StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _45 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _43 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &i32
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) }
- _11 = _45; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _11 = _43; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
bb4: {
- StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_22); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_22); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_23); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _44 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _42 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &[&str; 3]
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
- _25 = _44; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = _25; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_24); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_27); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_28); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_29); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_30); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_31); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _23 = _42; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _22 = _23; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _21 = move _22 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_22); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_26); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_27); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_28); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_29); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_31); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _31 = _13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _30 = &_31; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_33); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _33 = _13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _33 = _14; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_32 = &_33; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_29.0: &&i32) = move _30; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_29.1: &&i32) = move _32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_34); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _34 = (_29.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_35); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _35 = _14; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _34 = &_35; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_31.0: &&i32) = move _32; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_31.1: &&i32) = move _34; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_34); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_32); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_36); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _36 = (_31.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _37 = (_31.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_38); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _40 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _35 = (_29.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_36); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_37); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _37 = _34; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_38); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _38 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_46); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_47); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _47 = _40; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_44); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_45); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _45 = _38; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _44 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _45) -> bb5; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb5: {
- StorageDead(_47); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_48); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_49); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _49 = _39; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_45); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_46); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_47); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _47 = _37; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _46 = transmute::<&&i32, &core::fmt::Opaque>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb6: {
- StorageDead(_49); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_48); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_46); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_40); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_39); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_41); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _43 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_47); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_36.0: &core::fmt::Opaque) = move _46; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_36.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _44; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_46); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_44); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_38); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_37); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _40 = _35; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_41); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _41 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_50); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_51); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _51 = _43; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_48); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_49); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _49 = _41; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _48 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _49) -> bb7; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb7: {
- StorageDead(_51); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_52); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_53); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _53 = _42; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_49); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_50); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_51); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _51 = _40; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _50 = transmute::<&&i32, &core::fmt::Opaque>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb8: {
- StorageDead(_53); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_52); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_50); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_43); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_42); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _30 = [move _38, move _41]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_41); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_38); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_37); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_36); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _29 = &_30; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _28 = _29; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _27 = move _28 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_28); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_54); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- _54 = _23; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_55); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- discriminant(_55) = 0; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_56); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- _56 = _27; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_22.0: &[&str]) = move _54; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_22.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _55; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_22.2: &[std::fmt::ArgumentV1]) = move _56; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_56); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_55); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_54); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_27); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_51); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_39.0: &core::fmt::Opaque) = move _50; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_39.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _48; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_50); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_48); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_41); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _28 = [move _36, move _39]; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_36); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_35); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_34); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _27 = &_28; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _26 = _27; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _25 = move _26 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_26); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_52); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _52 = _21; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_53); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_53) = 0; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_54); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _54 = _25; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.0: &[&str]) = move _52; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _53; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.2: &[std::fmt::ArgumentV1]) = move _54; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_54); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_53); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_52); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ core::panicking::panic_fmt(move _20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
- // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'r> fn(std::fmt::Arguments<'r>) -> ! {core::panicking::panic_fmt}, val: Value(Scalar(<ZST>)) }
}
}
let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _18: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _20: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _21: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _22: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _23: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _24: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _25: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _26: [&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _27: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _28: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _29: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let _30: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _31: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _20: std::fmt::Arguments; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _21: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _23: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _24: [&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _25: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _26: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _27: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _28: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _29: (&&i32, &&i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _30: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _31: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _32: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let _33: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _34: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _35: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _38: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _39: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _40: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _41: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _42: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _43: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _36: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _37: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _38: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _39: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _40: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _41: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _45: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _43: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 4 {
debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
debug right_val => _14; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _36: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _37: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _44: &[&str; 3]; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _34: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _35: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _42: &[&str; 3]; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 5 {
- debug arg0 => _36; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug arg1 => _37; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _39; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _40; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _46: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _47: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _48: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _49: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+ debug arg0 => _34; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug arg1 => _35; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 6 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _37; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _38; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _44: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _45: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _46: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _47: &&i32; // in scope 6 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 7 {
}
}
- scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug x => _42; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug f => _43; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _50: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _51: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _52: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _53: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 8 (inlined ArgumentV1::new::<&i32>) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug x => _40; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug f => _41; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _48: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _49: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _50: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _51: &&i32; // in scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 9 {
}
}
}
- scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/std/src/macros.rs:LL:COL
- debug pieces => _23; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- debug args => _27; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _54: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _55: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- let mut _56: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+ scope 10 (inlined Arguments::new_v1) { // at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug pieces => _21; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug args => _25; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _52: &[&str]; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _53: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _54: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
}
}
StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _45 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _43 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &i32
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) }
- _11 = _45; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _11 = _43; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
bb4: {
- StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_22); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_22); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_23); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _44 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _42 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// ty::Const
// + ty: &[&str; 3]
// + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
- _25 = _44; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = _25; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_24); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_27); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_28); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_29); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_30); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_31); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ _23 = _42; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _22 = _23; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _21 = move _22 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_22); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_26); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_27); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_28); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_29); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_31); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _31 = _13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _30 = &_31; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_33); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _33 = _13; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _33 = _14; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_32 = &_33; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_29.0: &&i32) = move _30; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_29.1: &&i32) = move _32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_34); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _34 = (_29.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_35); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _35 = _14; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _34 = &_35; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_31.0: &&i32) = move _32; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_31.1: &&i32) = move _34; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_34); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_32); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_36); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _36 = (_31.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _37 = (_31.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_38); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _40 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _35 = (_29.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_36); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_37); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _37 = _34; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_38); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _38 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_46); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_47); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _47 = _40; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_44); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_45); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _45 = _38; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _44 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _45) -> bb5; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb5: {
- StorageDead(_47); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_48); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_49); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _49 = _39; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_45); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_46); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_47); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _47 = _37; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _46 = transmute::<&&i32, &core::fmt::Opaque>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb6: {
- StorageDead(_49); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_48); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_46); // scope 7 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_40); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_39); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_41); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _43 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_47); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_36.0: &core::fmt::Opaque) = move _46; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_36.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _44; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_46); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_44); // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_38); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_37); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _40 = _35; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_41); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _41 = <&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)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
- StorageLive(_50); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_51); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _51 = _43; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_48); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_49); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _49 = _41; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _48 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _49) -> bb7; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}
bb7: {
- StorageDead(_51); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_52); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_53); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _53 = _42; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_49); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_50); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_51); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _51 = _40; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _50 = transmute::<&&i32, &core::fmt::Opaque>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}
bb8: {
- StorageDead(_53); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_52); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_50); // scope 9 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_43); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_42); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- _30 = [move _38, move _41]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_41); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_38); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_37); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_36); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _29 = &_30; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _28 = _29; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _27 = move _28 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_28); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_54); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- _54 = _23; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_55); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- discriminant(_55) = 0; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageLive(_56); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- _56 = _27; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_22.0: &[&str]) = move _54; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_22.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _55; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- (_22.2: &[std::fmt::ArgumentV1]) = move _56; // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_56); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_55); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_54); // scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_27); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageDead(_51); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_39.0: &core::fmt::Opaque) = move _50; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_39.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _48; // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_50); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_48); // scope 9 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_41); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _28 = [move _36, move _39]; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_36); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_35); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_34); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _27 = &_28; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _26 = _27; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _25 = move _26 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_26); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_52); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _52 = _21; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_53); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_53) = 0; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_54); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _54 = _25; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.0: &[&str]) = move _52; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _53; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_20.2: &[std::fmt::ArgumentV1]) = move _54; // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_54); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_53); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_52); // scope 10 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_25); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ core::panicking::panic_fmt(move _20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
- // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'r> fn(std::fmt::Arguments<'r>) -> ! {core::panicking::panic_fmt}, val: Value(Scalar(<ZST>)) }
}
}
let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68
let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84
let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84
- let mut _22: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+ let mut _22: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
debug v => _2; // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10
let _13: &T; // in scope 1 at $DIR/issue_76432.rs:9:10: 9:16
}
bb1: {
- StorageLive(_22); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL
- begin_panic::<&str>(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL
+ StorageLive(_22); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// mir::Constant
- // + span: $SRC_DIR/std/src/macros.rs:LL:COL
- // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar(<ZST>)) }
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
// ty::Const
// + ty: &str
// + val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 })
--- /dev/null
+- // MIR for `non_const` before LowerIntrinsics
++ // MIR for `non_const` after LowerIntrinsics
+
+ fn non_const() -> usize {
+ let mut _0: usize; // return place in scope 0 at $DIR/lower_intrinsics.rs:55:26: 55:31
+ let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}; // in scope 0 at $DIR/lower_intrinsics.rs:57:9: 57:18
+ let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}; // in scope 0 at $DIR/lower_intrinsics.rs:58:5: 58:14
+ scope 1 {
+ debug size_of_t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:57:9: 57:18
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:57:9: 57:18
+ _1 = std::intrinsics::size_of::<T>; // scope 0 at $DIR/lower_intrinsics.rs:57:21: 57:51
+ // mir::Constant
+ // + span: $DIR/lower_intrinsics.rs:57:21: 57:51
+ // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(Scalar(<ZST>)) }
+ StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:14
+ _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:14
+- _0 = move _2() -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:16
++ _0 = SizeOf(T); // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:16
++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:58:5: 58:16
+ }
+
+ bb1: {
+ StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:58:15: 58:16
+ StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:59:1: 59:2
+ return; // scope 0 at $DIR/lower_intrinsics.rs:59:2: 59:2
+ }
+ }
+
#[inline(never)]
pub fn f_non_zst<T>(t: T) {}
+
+// EMIT_MIR lower_intrinsics.non_const.LowerIntrinsics.diff
+pub fn non_const<T>() -> usize {
+ // Check that lowering works with non-const operand as a func.
+ let size_of_t = core::intrinsics::size_of::<T>;
+ size_of_t()
+}
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
// pp-exact
INSTR_PROF_DATA_SUFFIX=,regular,live_support
DATA_SECTION_PREFIX=__DATA,
LLVM_COV_SECTION_PREFIX=__LLVM_COV,
+ COMDAT_IF_SUPPORTED=
else
INSTR_PROF_DATA_SUFFIX=
DATA_SECTION_PREFIX=
LLVM_COV_SECTION_PREFIX=
+ COMDAT_IF_SUPPORTED=, comdat
endif
ifeq ($(LINK_DEAD_CODE),yes)
-check-prefixes=CHECK,WINDOWS \
-DPRIVATE_GLOBAL='internal global' \
-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
+ -DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \
-DINSTR_PROF_DATA='.lprfd$$M' \
-DINSTR_PROF_NAME='.lprfn$$M' \
-DINSTR_PROF_CNTS='.lprfc$$M' \
-DINSTR_PROF_VALS='.lprfv$$M' \
-DINSTR_PROF_VNODES='.lprfnd$$M' \
-DINSTR_PROF_COVMAP='.lcovmap$$M' \
+ -DINSTR_PROF_COVFUN='.lcovfun$$M' \
-DINSTR_PROF_ORDERFILE='.lorderfile$$M'
else
LLVM_FILECHECK_OPTIONS=\
-check-prefixes=CHECK \
-DPRIVATE_GLOBAL='private global' \
-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
+ -DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \
-DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \
-DINSTR_PROF_NAME='$(DATA_SECTION_PREFIX)__llvm_prf_names' \
-DINSTR_PROF_CNTS='$(DATA_SECTION_PREFIX)__llvm_prf_cnts' \
-DINSTR_PROF_VALS='$(DATA_SECTION_PREFIX)__llvm_prf_vals' \
-DINSTR_PROF_VNODES='$(DATA_SECTION_PREFIX)__llvm_prf_vnds' \
-DINSTR_PROF_COVMAP='$(LLVM_COV_SECTION_PREFIX)__llvm_covmap' \
+ -DINSTR_PROF_COVFUN='$(LLVM_COV_SECTION_PREFIX)__llvm_covfun' \
-DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile'
endif
+ifeq ($(LLVM_VERSION_11_PLUS),true)
+all: test_llvm_ir
+else
+$(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.)
all:
+endif
+
+test_llvm_ir:
# Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR
#
# Note: `-Clink-dead-code=no` disables the option, needed because the option is automatically
-Clink-dead-code=$(LINK_DEAD_CODE) \
--emit=llvm-ir
- cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS)
+ cat "$(TMPDIR)"/testprog.ll | \
+ "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS)
WINDOWS: $__llvm_profile_runtime_user = comdat any
-CHECK: @__llvm_coverage_mapping = internal constant
+CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant
+CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
+
+CHECK: @__llvm_coverage_mapping = private constant
CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8
WINDOWS: @__llvm_profile_runtime = external global i32
# `llvm/release_debuginfo`. Note that some CI builds disable debug assertions (by setting
# `NO_LLVM_ASSERTIONS=1`), so it is not OK to fail the test, but `bless`ed test results cannot be
# generated without debug assertions.
-LLVM_COV_DEBUG := $(shell "$(LLVM_BIN_DIR)"/llvm-cov show --debug 2>&1 | grep -q "Unknown command line argument '--debug'"; echo $$?)
+LLVM_COV_DEBUG := $(shell \
+ "$(LLVM_BIN_DIR)"/llvm-cov show --debug 2>&1 | \
+ grep -q "Unknown command line argument '--debug'"; \
+ echo $$?)
ifeq ($(LLVM_COV_DEBUG), 1)
DEBUG_FLAG=--debug
endif
DEBUG_FLAG=--debug
endif
+ifeq ($(LLVM_VERSION_11_PLUS),true)
all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
+else
+$(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.)
+all:
+endif
# Ensure there are no `expected` results for tests that may have been removed or renamed
.PHONY: clear_expected_if_blessed
endef
export SPANVIEW_HEADER
+ifeq ($(LLVM_VERSION_11_PLUS),true)
all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
+else
+$(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.)
+all:
+endif
# Ensure there are no `expected` results for tests that may have been removed or renamed
.PHONY: clear_expected_if_blessed
UNAME = $(shell uname)
+# Rust option `-Z instrument-coverage` uses LLVM Coverage Mapping Format version 4,
+# which requires LLVM 11 or greater.
+LLVM_VERSION_11_PLUS := $(shell \
+ LLVM_VERSION=$$("$(LLVM_BIN_DIR)"/llvm-config --version) && \
+ LLVM_VERSION_MAJOR=$${LLVM_VERSION/.*/} && \
+ [ $$LLVM_VERSION_MAJOR -ge 11 ] && echo true || echo false)
+
# FIXME(richkadel): Can any of the features tested by `run-make-fulldeps/coverage-*` tests be tested
# just as completely by more focused unit tests of the code logic itself, to reduce the number of
# test result files generated and maintained, and to help identify specific test failures and root
#![crate_type = "lib"]
// we can compile to a variety of platforms, because we don't need
// cross-compiled standard libraries.
-#![feature(no_core, optin_builtin_traits)]
+#![feature(no_core, auto_traits)]
#![no_core]
#![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items, rustc_attrs)]
-#![feature(lang_items, no_core, optin_builtin_traits)]
+#![feature(lang_items, no_core, auto_traits)]
#![no_core]
#[lang="copy"]
-// ignore-cloudabi
// ignore-emscripten
// ignore-sgx no processes
// ignore-macos this needs valgrind 3.11 or higher; see
-#![feature(doc_alias)]
-
#[doc(alias = "true")]
pub struct Foo;
-#![feature(doc_alias)]
-
#[doc(alias = "true")]
pub struct Foo;
-#![feature(doc_alias)]
-
#[doc(alias = "Demon Lord")]
pub struct Struct;
-#![feature(doc_alias)]
-
#[doc(alias = "StructItem")]
pub struct Struct {
#[doc(alias = "StructFieldItem")]
-#![feature(doc_alias)]
-
pub struct Bar;
pub trait Foo {
type X;
error: `#[doc(alias = "...")]` isn't allowed on extern block
- --> $DIR/check-doc-alias-attr-location.rs:9:7
+ --> $DIR/check-doc-alias-attr-location.rs:7:7
|
LL | #[doc(alias = "foo")]
| ^^^^^^^^^^^^^
error: `#[doc(alias = "...")]` isn't allowed on implementation block
- --> $DIR/check-doc-alias-attr-location.rs:12:7
+ --> $DIR/check-doc-alias-attr-location.rs:10:7
|
LL | #[doc(alias = "bar")]
| ^^^^^^^^^^^^^
error: `#[doc(alias = "...")]` isn't allowed on implementation block
- --> $DIR/check-doc-alias-attr-location.rs:18:7
+ --> $DIR/check-doc-alias-attr-location.rs:16:7
|
LL | #[doc(alias = "foobar")]
| ^^^^^^^^^^^^^^^^
error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation block
- --> $DIR/check-doc-alias-attr-location.rs:20:11
+ --> $DIR/check-doc-alias-attr-location.rs:18:11
|
LL | #[doc(alias = "assoc")]
| ^^^^^^^^^^^^^^^
#![crate_type = "lib"]
-#![feature(doc_alias)]
#[doc(alias = "foo")] // ok!
pub struct Bar;
error: doc alias attribute expects a string: #[doc(alias = "0")]
- --> $DIR/check-doc-alias-attr.rs:7:7
+ --> $DIR/check-doc-alias-attr.rs:6:7
|
LL | #[doc(alias)]
| ^^^^^
error: doc alias attribute expects a string: #[doc(alias = "0")]
- --> $DIR/check-doc-alias-attr.rs:8:7
+ --> $DIR/check-doc-alias-attr.rs:7:7
|
LL | #[doc(alias = 0)]
| ^^^^^^^^^
error: doc alias attribute expects a string: #[doc(alias = "0")]
- --> $DIR/check-doc-alias-attr.rs:9:7
+ --> $DIR/check-doc-alias-attr.rs:8:7
|
LL | #[doc(alias("bar"))]
| ^^^^^^^^^^^^
error: '\"' character isn't allowed in `#[doc(alias = "...")]`
- --> $DIR/check-doc-alias-attr.rs:10:7
+ --> $DIR/check-doc-alias-attr.rs:9:7
|
LL | #[doc(alias = "\"")]
| ^^^^^^^^^^^^
error: '\n' character isn't allowed in `#[doc(alias = "...")]`
- --> $DIR/check-doc-alias-attr.rs:11:7
+ --> $DIR/check-doc-alias-attr.rs:10:7
|
LL | #[doc(alias = "\n")]
| ^^^^^^^^^^^^
error: '\n' character isn't allowed in `#[doc(alias = "...")]`
- --> $DIR/check-doc-alias-attr.rs:12:7
+ --> $DIR/check-doc-alias-attr.rs:11:7
|
LL | #[doc(alias = "
| _______^
| |_^
error: '\t' character isn't allowed in `#[doc(alias = "...")]`
- --> $DIR/check-doc-alias-attr.rs:14:7
+ --> $DIR/check-doc-alias-attr.rs:13:7
|
LL | #[doc(alias = "\t")]
| ^^^^^^^^^^^^
error: `#[doc(alias = "...")]` cannot start or end with ' '
- --> $DIR/check-doc-alias-attr.rs:15:7
+ --> $DIR/check-doc-alias-attr.rs:14:7
|
LL | #[doc(alias = " hello")]
| ^^^^^^^^^^^^^^^^
error: `#[doc(alias = "...")]` cannot start or end with ' '
- --> $DIR/check-doc-alias-attr.rs:16:7
+ --> $DIR/check-doc-alias-attr.rs:15:7
|
LL | #[doc(alias = "hello ")]
| ^^^^^^^^^^^^^^^^
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
-| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 100.0% | 0 | 0.0% |
-| <anon> | 2 | 100.0% | 0 | 0.0% |
+| ...st/rustdoc-ui/coverage/exotic.rs | 3 | 100.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+
| Total | 3 | 100.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+
-#![feature(doc_alias)]
#![feature(trait_alias)]
pub struct Foo;
error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block
- --> $DIR/doc-alias-assoc-const.rs:11:11
+ --> $DIR/doc-alias-assoc-const.rs:10:11
|
LL | #[doc(alias = "CONST_BAZ")]
| ^^^^^^^^^^^^^^^^^^^
// compile-flags:--test
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
-#![feature(cfg_doctest)]
-
// Make sure `cfg(doctest)` is set when finding doctests but not inside
// the doctests.
/// ```
-/// #![feature(cfg_doctest)]
/// assert!(!cfg!(doctest));
/// ```
#[cfg(doctest)]
running 1 test
-test $DIR/doc-test-doctest-feature.rs - Foo (line 10) ... ok
+test $DIR/doc-test-doctest-feature.rs - Foo (line 8) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
LL | #![deny(missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: missing code example in this documentation
- --> $DIR/doc-without-codeblock.rs:3:1
- |
-LL | /// Some docs.
- | ^^^^^^^^^^^^^^
-
error: missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:7:1
|
LL | /// Or maybe not because she saved herself!
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: missing code example in this documentation
+ --> $DIR/doc-without-codeblock.rs:3:1
+ |
+LL | /// Some docs.
+ | ^^^^^^^^^^^^^^
+
error: aborting due to 4 previous errors
| this link resolves to the struct `S`, which is not in the macro namespace
| help: to link to the struct, prefix with `struct@`: `struct@S`
+error: unresolved link to `S::h`
+ --> $DIR/intra-link-errors.rs:78:6
+ |
+LL | /// [type@S::h]
+ | ^^^^^^^^^
+ | |
+ | this link resolves to the associated function `h`, which is not in the type namespace
+ | help: to link to the associated function, add parentheses: `S::h()`
+
error: unresolved link to `T::g`
--> $DIR/intra-link-errors.rs:86:6
|
LL | /// [T::h!]
| ^^^^^ the trait `T` has no macro named `h`
-error: unresolved link to `S::h`
- --> $DIR/intra-link-errors.rs:78:6
- |
-LL | /// [type@S::h]
- | ^^^^^^^^^
- | |
- | this link resolves to the associated function `h`, which is not in the type namespace
- | help: to link to the associated function, add parentheses: `S::h()`
-
error: unresolved link to `m`
--> $DIR/intra-link-errors.rs:98:6
|
-error: `ambiguous` is both a struct and a function
- --> $DIR/intra-links-ambiguity.rs:27:6
+error: `true` is both a module and a builtin type
+ --> $DIR/intra-links-ambiguity.rs:38:6
|
-LL | /// [`ambiguous`] is ambiguous.
- | ^^^^^^^^^^^ ambiguous link
+LL | /// [true]
+ | ^^^^ ambiguous link
|
note: the lint level is defined here
--> $DIR/intra-links-ambiguity.rs:1:9
|
LL | #![deny(broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the module, prefix with `mod@`
+ |
+LL | /// [mod@true]
+ | ^^^^^^^^
+help: to link to the builtin type, prefix with `prim@`
+ |
+LL | /// [prim@true]
+ | ^^^^^^^^^
+
+error: `ambiguous` is both a struct and a function
+ --> $DIR/intra-links-ambiguity.rs:27:6
+ |
+LL | /// [`ambiguous`] is ambiguous.
+ | ^^^^^^^^^^^ ambiguous link
+ |
help: to link to the struct, prefix with `struct@`
|
LL | /// [`struct@ambiguous`] is ambiguous.
LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
| ^^^^^^^^^^^^
-error: `true` is both a module and a builtin type
- --> $DIR/intra-links-ambiguity.rs:38:6
- |
-LL | /// [true]
- | ^^^^ ambiguous link
- |
-help: to link to the module, prefix with `mod@`
- |
-LL | /// [mod@true]
- | ^^^^^^^^
-help: to link to the builtin type, prefix with `prim@`
- |
-LL | /// [prim@true]
- | ^^^^^^^^^
-
error: aborting due to 6 previous errors
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+warning: unresolved link to `BarA`
+ --> $DIR/intra-links-warning.rs:21:10
+ |
+LL | /// bar [BarA] bar
+ | ^^^^ no item named `BarA` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarB`
+ --> $DIR/intra-links-warning.rs:27:9
+ |
+LL | * bar [BarB] bar
+ | ^^^^ no item named `BarB` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarC`
+ --> $DIR/intra-links-warning.rs:34:6
+ |
+LL | bar [BarC] bar
+ | ^^^^ no item named `BarC` in scope
+ |
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarD`
+ --> $DIR/intra-links-warning.rs:45:1
+ |
+LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the link appears in this line:
+
+ bar [BarD] bar
+ ^^^^
+ = note: no item named `BarD` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarF`
+ --> $DIR/intra-links-warning.rs:50:9
+ |
+LL | #[doc = $f]
+ | ^^^^^^^^^^^
+...
+LL | f!("Foo\nbar [BarF] bar\nbaz");
+ | ------------------------------- in this macro invocation
+ |
+ = note: the link appears in this line:
+
+ bar [BarF] bar
+ ^^^^
+ = note: no item named `BarF` in scope
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+ = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:58:30
|
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: unresolved link to `BarA`
- --> $DIR/intra-links-warning.rs:21:10
- |
-LL | /// bar [BarA] bar
- | ^^^^ no item named `BarA` in scope
- |
- = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarB`
- --> $DIR/intra-links-warning.rs:27:9
- |
-LL | * bar [BarB] bar
- | ^^^^ no item named `BarB` in scope
- |
- = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarC`
- --> $DIR/intra-links-warning.rs:34:6
- |
-LL | bar [BarC] bar
- | ^^^^ no item named `BarC` in scope
- |
- = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarD`
- --> $DIR/intra-links-warning.rs:45:1
- |
-LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: the link appears in this line:
-
- bar [BarD] bar
- ^^^^
- = note: no item named `BarD` in scope
- = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarF`
- --> $DIR/intra-links-warning.rs:50:9
- |
-LL | #[doc = $f]
- | ^^^^^^^^^^^
-...
-LL | f!("Foo\nbar [BarF] bar\nbaz");
- | ------------------------------- in this macro invocation
- |
- = note: the link appears in this line:
-
- bar [BarF] bar
- ^^^^
- = note: no item named `BarF` in scope
- = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
- = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
warning: 19 warnings emitted
error: missing code example in this documentation
- --> $DIR/lint-missing-doc-code-example.rs:49:1
+ --> $DIR/lint-missing-doc-code-example.rs:19:1
|
-LL | /// Doc
- | ^^^^^^^
+LL | / mod module1 {
+LL | | }
+ | |_^
|
note: the lint level is defined here
--> $DIR/lint-missing-doc-code-example.rs:2:9
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing code example in this documentation
- --> $DIR/lint-missing-doc-code-example.rs:63:1
+ --> $DIR/lint-missing-doc-code-example.rs:37:3
|
-LL | /// Doc
- | ^^^^^^^
+LL | /// doc
+ | ^^^^^^^
error: missing code example in this documentation
- --> $DIR/lint-missing-doc-code-example.rs:56:1
+ --> $DIR/lint-missing-doc-code-example.rs:49:1
|
LL | /// Doc
| ^^^^^^^
error: missing code example in this documentation
- --> $DIR/lint-missing-doc-code-example.rs:19:1
+ --> $DIR/lint-missing-doc-code-example.rs:56:1
|
-LL | / mod module1 {
-LL | | }
- | |_^
+LL | /// Doc
+ | ^^^^^^^
error: missing code example in this documentation
- --> $DIR/lint-missing-doc-code-example.rs:37:3
+ --> $DIR/lint-missing-doc-code-example.rs:63:1
|
-LL | /// doc
- | ^^^^^^^
+LL | /// Doc
+ | ^^^^^^^
error: aborting due to 5 previous errors
// aux-build:auto-traits.rs
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![crate_name = "foo"]
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
// @has auto_aliases/trait.Bar.html '//h3[@aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
pub struct Foo;
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
pub unsafe auto trait Bar {}
--- /dev/null
+#![crate_name = "inner"]
+pub trait MyTrait {
+ type Y;
+}
+
+impl MyTrait for u32 {
+ type Y = i32;
+}
+
+pub fn foo() -> <u32 as MyTrait>::Y {
+ 0
+}
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
pub mod bar {
use std::marker;
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
-pub auto trait AnOibit {}
+pub auto trait AnAutoTrait {}
-#![feature(deprecated)]
-
// @has deprecated_future/index.html '//*[@class="stab deprecated"]' \
// 'Deprecated'
// @has deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \
-#![feature(deprecated)]
-
// @has deprecated/index.html '//*[@class="docblock-short"]/span[@class="stab deprecated"]' \
// 'Deprecated'
// @has - '//*[@class="docblock-short"]' 'Deprecated docs'
// full impl string. Instead, just make sure something from each part
// is mentioned.
-// @has implementors/rustdoc_impl_parts_crosscrate/trait.AnOibit.js Bar
+// @has implementors/rustdoc_impl_parts_crosscrate/trait.AnAutoTrait.js Bar
// @has - Send
-// @has - !AnOibit
+// @has - !AnAutoTrait
// @has - Copy
-impl<T: Send> !rustdoc_impl_parts_crosscrate::AnOibit for Bar<T>
+impl<T: Send> !rustdoc_impl_parts_crosscrate::AnAutoTrait for Bar<T>
where T: Copy {}
#![feature(negative_impls)]
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
-pub auto trait AnOibit {}
+pub auto trait AnAutoTrait {}
pub struct Foo<T> { field: T }
// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \
-// "impl<T: Clone> !AnOibit for Foo<T> where T: Sync,"
-// @has impl_parts/trait.AnOibit.html '//*[@class="item-list"]//code' \
-// "impl<T: Clone> !AnOibit for Foo<T> where T: Sync,"
-impl<T: Clone> !AnOibit for Foo<T> where T: Sync {}
+// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//code' \
+// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
// aux-build:impl_trait_aux.rs
// edition:2018
+// ignore-tidy-linelength
extern crate impl_trait_aux;
// @has impl_trait/fn.func.html
-// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a)"
+// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
// @!has - '//pre[@class="rust fn"]' 'where'
pub use impl_trait_aux::func;
pub use impl_trait_aux::async_fn;
// @has impl_trait/struct.Foo.html
-// @has - '//*[@id="method.method"]//code' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a)"
+// @has - '//*[@id="method.method"]//code' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
// @!has - '//*[@id="method.method"]//code' 'where'
pub use impl_trait_aux::Foo;
// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
+//! And [`Result<T, !>`] and [`Result<!, E>`].
//!
// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<!, E>'
//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
--- /dev/null
+#![feature(extern_types)]
+
+extern {
+ pub type ExternType;
+}
+
+impl ExternType {
+ pub fn f(&self) {
+
+ }
+}
+
+// @has 'intra_link_extern_type/foreigntype.ExternType.html'
+// @has 'intra_link_extern_type/fn.links_to_extern_type.html' \
+// 'href="../intra_link_extern_type/foreigntype.ExternType.html#method.f"'
+/// See also [ExternType::f]
+pub fn links_to_extern_type() {
+}
-#![feature(const_fn)]
-
// @has 'issue_76501/fn.bloop.html' '//pre' 'pub const fn bloop() -> i32'
/// A useless function that always returns 1.
pub const fn bloop() -> i32 {
--- /dev/null
+// ignore-tidy-linelength
+// aux-build:normalize-assoc-item.rs
+// build-aux-docs
+// ignore-test
+
+pub trait Trait {
+ type X;
+}
+
+impl Trait for usize {
+ type X = isize;
+}
+
+// @has 'normalize_assoc_item/fn.f.html' '//pre[@class="rust fn"]' 'pub fn f() -> isize'
+pub fn f() -> <usize as Trait>::X {
+ 0
+}
+
+pub struct S {
+ // @has 'normalize_assoc_item/struct.S.html' '//span[@id="structfield.box_me_up"]' 'box_me_up: Box<S, Global>'
+ pub box_me_up: <S as Trait>::X,
+ // @has 'normalize_assoc_item/struct.S.html' '//span[@id="structfield.generic"]' 'generic: (usize, isize)'
+ pub generic: <Generic<usize> as Trait>::X,
+}
+
+impl Trait for S {
+ type X = Box<S>;
+}
+
+pub struct Generic<Inner>(Inner);
+
+impl<Inner: Trait> Trait for Generic<Inner> {
+ type X = (Inner, Inner::X);
+}
+
+// These can't be normalized because they depend on a generic parameter.
+// However the user can choose whether the text should be displayed as `Inner::X` or `<Inner as Trait>::X`.
+
+// @has 'normalize_assoc_item/struct.Unknown.html' '//pre[@class="rust struct"]' 'pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);'
+pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);
+
+// @has 'normalize_assoc_item/struct.Unknown2.html' '//pre[@class="rust struct"]' 'pub struct Unknown2<Inner: Trait>(pub Inner::X);'
+pub struct Unknown2<Inner: Trait>(pub Inner::X);
+
+trait Lifetimes<'a> {
+ type Y;
+}
+
+impl<'a> Lifetimes<'a> for usize {
+ type Y = &'a isize;
+}
+
+// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust fn"]' "pub fn g() -> &isize"
+pub fn g() -> <usize as Lifetimes<'static>>::Y {
+ &0
+}
+
+// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust const"]' "pub const A: &isize"
+pub const A: <usize as Lifetimes<'static>>::Y = &0;
+
+// test cross-crate re-exports
+extern crate inner;
+// @has 'normalize_assoc_item/fn.foo.html' '//pre[@class="rust fn"]' "pub fn foo() -> i32"
+pub use inner::foo;
+
+// @has 'normalize_assoc_item/fn.h.html' '//pre[@class="rust fn"]' "pub fn h<T>() -> IntoIter<T, Global>"
+pub fn h<T>() -> <Vec<T> as IntoIterator>::IntoIter {
+ vec![].into_iter()
+}
// @has foo/hidden/struct.Foo.html
// @has - '//p/a' '../../foo/struct.FooBar.html'
pub struct Foo {}
+ pub union U { a: usize }
+ pub enum Empty {}
+ pub const C: usize = 1;
+ pub static S: usize = 1;
// @has foo/hidden/bar/index.html
// @has - '//p/a' '../../foo/baz/index.html'
// @has foo/struct.FooBar.html
pub use hidden::Foo as FooBar;
+// @has foo/union.FooU.html
+pub use hidden::U as FooU;
+// @has foo/enum.FooEmpty.html
+pub use hidden::Empty as FooEmpty;
+// @has foo/constant.FooC.html
+pub use hidden::C as FooC;
+// @has foo/static.FooS.html
+pub use hidden::S as FooS;
// @has foo/baz/index.html
// @has foo/baz/struct.Thing.html
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
pub auto trait Banana {}
--- /dev/null
+#![crate_name = "quix"]
+pub trait Foo {
+ // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' '[src]'
+ fn required();
+
+ // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' '[src]'
+ fn provided() {}
+}
+
+pub struct Bar;
+
+impl Foo for Bar {
+ // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' '[src]'
+ fn required() {}
+ // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' '[src]'
+}
+
+pub struct Baz;
+
+impl Foo for Baz {
+ // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' '[src]'
+ fn required() {}
+
+ // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' '[src]'
+ fn provided() {}
+}
--- /dev/null
+#![feature(unboxed_closures)]
+
+extern "rust-call" fn b(_i: i32) {}
+//~^ ERROR A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+
+fn main () {
+ b(10);
+}
--- /dev/null
+error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+ --> $DIR/issue-22565-rust-call.rs:3:1
+ |
+LL | extern "rust-call" fn b(_i: i32) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+#![feature(unboxed_closures)]
+
+extern "rust-call" fn foo<T>(_: T) {}
+
+fn main() {
+ foo(());
+ foo((1, 2));
+}
// run-pass
#![allow(unused_imports)]
-// ignore-cloudabi can't run commands
// ignore-emscripten can't run commands
// ignore-sgx no processes
// ignore-sparc
// ignore-sparc64
// ignore-wasm
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-musl FIXME #31506
// ignore-sparc
// ignore-sparc64
// ignore-wasm
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// run-pass
// ignore-android no libc
-// ignore-cloudabi no libc
// ignore-emscripten no libc
// ignore-sgx no libc
// ignore-wasm32 no libc
// run-pass
// ignore-android no libc
-// ignore-cloudabi no libc
// ignore-emscripten no libc
// ignore-sgx no libc
// ignore-wasm32 no libc
--- /dev/null
+// Checks that #[naked] attribute can be placed on function definitions only.
+//
+// ignore-wasm32 asm unsupported
+#![feature(asm)]
+#![feature(naked_functions)]
+#![naked] //~ ERROR should be applied to a function definition
+
+extern "C" {
+ #[naked] //~ ERROR should be applied to a function definition
+ fn f();
+}
+
+#[naked] //~ ERROR should be applied to a function definition
+#[repr(C)]
+struct S {
+ a: u32,
+ b: u32,
+}
+
+trait Invoke {
+ #[naked] //~ ERROR should be applied to a function definition
+ extern "C" fn invoke(&self);
+}
+
+impl Invoke for S {
+ #[naked]
+ extern "C" fn invoke(&self) {
+ unsafe { asm!("", options(noreturn)) }
+ }
+}
+
+#[naked]
+extern "C" fn ok() {
+ unsafe { asm!("", options(noreturn)) }
+}
+
+impl S {
+ #[naked]
+ extern "C" fn g() {
+ unsafe { asm!("", options(noreturn)) }
+ }
+
+ #[naked]
+ extern "C" fn h(&self) {
+ unsafe { asm!("", options(noreturn)) }
+ }
+}
+
+fn main() {
+ #[naked] || {}; //~ ERROR should be applied to a function definition
+}
--- /dev/null
+error: attribute should be applied to a function definition
+ --> $DIR/naked-invalid-attr.rs:13:1
+ |
+LL | #[naked]
+ | ^^^^^^^^
+LL | #[repr(C)]
+LL | / struct S {
+LL | | a: u32,
+LL | | b: u32,
+LL | | }
+ | |_- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/naked-invalid-attr.rs:50:5
+ |
+LL | #[naked] || {};
+ | ^^^^^^^^ ----- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/naked-invalid-attr.rs:21:5
+ |
+LL | #[naked]
+ | ^^^^^^^^
+LL | extern "C" fn invoke(&self);
+ | ---------------------------- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/naked-invalid-attr.rs:9:5
+ |
+LL | #[naked]
+ | ^^^^^^^^
+LL | fn f();
+ | ------- not a function definition
+
+error: attribute should be applied to a function definition
+ --> $DIR/naked-invalid-attr.rs:6:1
+ |
+LL | #![naked]
+ | ^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+// Check that use of function parameters is validate in naked functions.
+//
+// ignore-wasm32 asm unsupported
+#![feature(asm)]
+#![feature(naked_functions)]
+#![feature(or_patterns)]
+#![crate_type = "lib"]
+
+#[repr(C)]
+pub struct P { x: u8, y: u16 }
+
+#[naked]
+pub unsafe extern "C" fn f(
+ mut a: u32,
+ //~^ ERROR patterns not allowed in naked function parameters
+ &b: &i32,
+ //~^ ERROR patterns not allowed in naked function parameters
+ (None | Some(_)): Option<std::ptr::NonNull<u8>>,
+ //~^ ERROR patterns not allowed in naked function parameters
+ P { x, y }: P,
+ //~^ ERROR patterns not allowed in naked function parameters
+) {
+ asm!("", options(noreturn))
+}
+
+#[naked]
+pub unsafe extern "C" fn inc(a: u32) -> u32 {
+ a + 1
+ //~^ ERROR use of parameters not allowed inside naked functions
+}
+
+#[naked]
+pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
+ asm!("/* {0} */", in(reg) a, options(noreturn));
+ //~^ ERROR use of parameters not allowed inside naked functions
+}
+
+#[naked]
+pub unsafe extern "C" fn sum(x: u32, y: u32) -> u32 {
+ // FIXME: Should be detected by asm-only check.
+ (|| { x + y})()
+}
+
+pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
+ #[naked]
+ pub extern "C" fn inner(y: usize) -> usize {
+ *&y
+ //~^ ERROR use of parameters not allowed inside naked functions
+ }
+ inner
+}
--- /dev/null
+error: patterns not allowed in naked function parameters
+ --> $DIR/naked-params.rs:14:5
+ |
+LL | mut a: u32,
+ | ^^^^^
+
+error: patterns not allowed in naked function parameters
+ --> $DIR/naked-params.rs:16:5
+ |
+LL | &b: &i32,
+ | ^^
+
+error: patterns not allowed in naked function parameters
+ --> $DIR/naked-params.rs:18:6
+ |
+LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
+ | ^^^^^^^^^^^^^^
+
+error: patterns not allowed in naked function parameters
+ --> $DIR/naked-params.rs:20:5
+ |
+LL | P { x, y }: P,
+ | ^^^^^^^^^^
+
+error: use of parameters not allowed inside naked functions
+ --> $DIR/naked-params.rs:28:5
+ |
+LL | a + 1
+ | ^
+
+error: use of parameters not allowed inside naked functions
+ --> $DIR/naked-params.rs:34:31
+ |
+LL | asm!("/* {0} */", in(reg) a, options(noreturn));
+ | ^
+
+error: use of parameters not allowed inside naked functions
+ --> $DIR/naked-params.rs:47:11
+ |
+LL | *&y
+ | ^
+
+error: aborting due to 7 previous errors
+
impl Tr1 for A {
type As1 = core::ops::Range<u8>;
fn mk(&self) -> Self::As1 { 0..10 }
- };
+ }
Box::new(A)
}
pub fn use_et3() {
impl Tr1 for A {
type As1 = core::ops::Range<u8>;
fn mk(&self) -> Self::As1 { 0..10 }
- };
+ }
&A
};
pub fn use_et3() {
impl Tr1 for A {
type As1 = core::ops::Range<u8>;
fn mk(&self) -> Self::As1 { 0..10 }
- };
+ }
let x /* : Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>> */
= Box::new(A);
x
impl Tr1 for A {
type As1 = core::ops::Range<u8>;
fn mk(&self) -> Self::As1 { 0..10 }
- };
+ }
let x: impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = A;
x
};
impl Tr1 for A {
type As1 = core::ops::Range<u8>;
fn mk(self) -> Self::As1 { 0..10 }
- };
+ }
A
}
impl Tr1 for A {
type As1 = core::ops::Range<u8>;
fn mk(self) -> Self::As1 { 0..10 }
- };
+ }
A
}
pub fn use_et3() {
|
::: $SRC_DIR/alloc/src/vec.rs:LL:COL
|
-LL | pub struct Vec<T> {
+LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> {
| - required by this bound in `Vec`
|
= help: the trait `Sized` is not implemented for `[u8]`
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
// edition:2018
#![allow(unused_must_use)]
#![allow(deprecated)]
-// ignore-cloudabi no process support
// ignore-emscripten no threads support
// ignore-sgx no processes
enum FooEnum {
#[test]
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
Bar(i32),
}
struct FooStruct {
#[test]
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
bar: i32,
}
match foo_struct {
FooStruct {
#[test] bar
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
} => {}
}
match 1 {
0 => {}
#[test]
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
_ => {}
}
let _another_foo_strunct = FooStruct {
#[test]
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
bar: 1,
};
}
-error: expected an inert attribute, found an attribute macro
- --> $DIR/attrs-resolution-errors.rs:2:5
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/attrs-resolution-errors.rs:2:7
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/attrs-resolution-errors.rs:8:5
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/attrs-resolution-errors.rs:8:7
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/attrs-resolution-errors.rs:23:13
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/attrs-resolution-errors.rs:23:15
|
LL | #[test] bar
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/attrs-resolution-errors.rs:30:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/attrs-resolution-errors.rs:30:11
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/attrs-resolution-errors.rs:36:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/attrs-resolution-errors.rs:36:11
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
error: aborting due to 5 previous errors
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
auto trait Generic<T> {}
//~^ auto traits cannot have generic parameters [E0567]
// run-pass
#![allow(unused_doc_comments)]
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait Auto {}
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
unsafe auto trait Trait {
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
unsafe auto trait Trait {
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait Magic : Sized where Option<Self> : Magic {} //~ ERROR E0568
// println!("{:?} {:?}", a, b);
// }
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait Magic: Copy {} //~ ERROR E0568
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait MyTrait {}
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait MyTrait {}
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait MyTrait {}
// other words, the auto impl only applies if there are no existing
// impls whose types unify.
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait Defaulted { }
--- /dev/null
+#[macro_export]
+macro_rules! fancy_panic {
+ ($msg:expr) => {
+ panic!($msg)
+ };
+}
// compile-flags:-g -Cllvm-args=-enable-tail-merge=0 -Cllvm-args=-opt-bisect-limit=0
// compile-flags:-Cforce-frame-pointers=yes
// ignore-pretty issue #37195
-// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
// ignore-sgx no processes
// normalize-stderr-test ".*\n" -> ""
// run-pass
// ignore-android FIXME #17520
-// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
// ignore-openbsd no support for libbacktrace without filename
// ignore-sgx no processes
|
::: $SRC_DIR/alloc/src/vec.rs:LL:COL
|
-LL | pub struct Vec<T> {
+LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> {
| - required by this bound in `Vec`
|
= help: the trait `Sized` is not implemented for `dyn Trait`
// run-pass
// pretty-expanded FIXME #23616
-// ignore-cloudabi no target_family
// ignore-wasm32-bare no target_family
// ignore-sgx
// run-pass
-// ignore-cloudabi no target_family
// ignore-wasm32-bare no target_family
// ignore-sgx
// Test that cleanups for the RHS of shortcircuiting operators work.
// pretty-expanded FIXME #23616
-// ignore-cloudabi no std::env support
use std::env;
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait MySafeTrait {}
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
// Test for issue #56934 - that it is impossible to redundantly
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
// Test for issue #56934 - that it is impossible to redundantly
// run-pass
// ignore-windows - this is a unix-specific test
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
use std::os::unix::process::CommandExt;
// run-pass
// ignore-windows - this is a unix-specific test
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
use std::env;
#![allow(stable_features)]
// ignore-windows - this is a unix-specific test
// ignore-pretty issue #37199
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
#![allow(stable_features)]
// ignore-windows - this is a unix-specific test
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
#![feature(process_exec, rustc_private)]
// run-pass
// ignore-android
-// ignore-cloudabi
// ignore-emscripten
// ignore-sgx
| ^
error: cannot find attribute `unknown` in this scope
- --> $DIR/cfg-generic-params.rs:34:43
+ --> $DIR/cfg-generic-params.rs:19:29
|
-LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
- | ^^^^^^^
+LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {}
+ | ^^^^^^^
error: cannot find attribute `unknown` in this scope
- --> $DIR/cfg-generic-params.rs:30:40
+ --> $DIR/cfg-generic-params.rs:22:29
|
-LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
- | ^^^^^^^
+LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {}
+ | ^^^^^^^
error: cannot find attribute `unknown` in this scope
--> $DIR/cfg-generic-params.rs:26:34
| ^^^^^^^
error: cannot find attribute `unknown` in this scope
- --> $DIR/cfg-generic-params.rs:22:29
+ --> $DIR/cfg-generic-params.rs:30:40
|
-LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {}
- | ^^^^^^^
+LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
+ | ^^^^^^^
error: cannot find attribute `unknown` in this scope
- --> $DIR/cfg-generic-params.rs:19:29
+ --> $DIR/cfg-generic-params.rs:34:43
|
-LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {}
- | ^^^^^^^
+LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
+ | ^^^^^^^
error: aborting due to 8 previous errors
#![feature(cfg_accessible)]
-#[cfg_accessible(Z)] //~ ERROR cannot determine whether the path is accessible or not
+#[cfg_accessible(Z)] // OK, recovered after the other `cfg_accessible` produces an error.
struct S;
#[cfg_accessible(S)] //~ ERROR cannot determine whether the path is accessible or not
LL | #[cfg_accessible(S)]
| ^^^^^^^^^^^^^^^^^^^^
-error: cannot determine whether the path is accessible or not
- --> $DIR/cfg_accessible-stuck.rs:3:1
- |
-LL | #[cfg_accessible(Z)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^^^ cannot perform const operation using `CFG`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 3 previous errors
| ^ 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: generic parameters may not be used in const operations
--> $DIR/const-arg-in-const-arg.rs:15:23
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ 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: generic parameters may not be used in const operations
--> $DIR/const-arg-in-const-arg.rs:31:24
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ 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: generic parameters may not be used in const operations
--> $DIR/const-arg-in-const-arg.rs:37:27
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ 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[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/const-argument-if-length.rs:17:12
| ^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 4 previous errors
| ^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 10 previous errors
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 4 previous errors
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 2 previous errors
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 2 previous errors
| ^ cannot perform const operation using `A`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `B`
|
= help: const parameters may only be used as standalone arguments, i.e. `B`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 2 previous errors
|
LL | foo();
| ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
+ |
+help: consider specifying the const argument
+ |
+LL | foo::<X>();
+ | ^^^^^^^^
error: aborting due to previous error
|
LL | foo();
| ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
+ |
+help: consider specifying the const argument
+ |
+LL | foo::<X>();
+ | ^^^^^^^^
error: aborting due to previous error
|
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`
+ |
+help: consider specifying the const argument
+ |
+LL | println!("{:?}", take_array_from_mut::<N>(&mut arr, i));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
|
LL | Foo.bar().bar().bar().bar().baz();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
+ |
+help: consider specifying the const argument
+ |
+LL | Foo.bar().bar().bar().bar().baz::<N>();
+ | ^^^^^^^^
error: aborting due to previous error
|
LL | Foo.bar().bar().bar().bar().baz();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
+ |
+help: consider specifying the const argument
+ |
+LL | Foo.bar().bar().bar().bar().baz::<N>();
+ | ^^^^^^^^
error: aborting due to previous error
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/one-param-uninferred.rs:15:23
+ |
+LL | let _: [u8; 17] = foo();
+ | ^^^ cannot infer the value of const parameter `M` declared on the function `foo`
+ |
+help: consider specifying the const argument
+ |
+LL | let _: [u8; 17] = foo::<M>();
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/one-param-uninferred.rs:15:23
+ |
+LL | let _: [u8; 17] = foo();
+ | ^^^ cannot infer the value of const parameter `M` declared on the function `foo`
+ |
+help: consider specifying the const argument
+ |
+LL | let _: [u8; 17] = foo::<M>();
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// Test that we emit an error if we cannot properly infer a constant.
+// 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 M: usize>() -> [u8; N] {
+ todo!()
+}
+
+fn main() {
+ // FIXME(const_generics): Currently this only suggests one const parameter,
+ // but instead it should suggest to provide all parameters.
+ let _: [u8; 17] = foo();
+ //~^ ERROR type annotations needed
+}
--> $DIR/uninferred-consts.rs:14:9
|
LL | Foo.foo();
- | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo`
+ | ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
+ |
+help: consider specifying the const argument
+ |
+LL | Foo.foo::<A>();
+ | ^^^^^^^^
error: aborting due to previous error
--> $DIR/uninferred-consts.rs:14:9
|
LL | Foo.foo();
- | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo`
+ | ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
+ |
+help: consider specifying the const argument
+ |
+LL | Foo.foo::<A>();
+ | ^^^^^^^^
error: aborting due to previous error
// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
struct Foo;
impl Foo {
- fn foo<const N: usize>(self) {}
+ fn foo<const A: usize, const B: usize>(self) {}
}
fn main() {
Foo.foo();
| ^ 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: `&'static str` is forbidden as the type of a const generic parameter
--> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
| ^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 2 previous errors
+use std::cell::Cell;
+
fn main() {
- let _: Vec<&str, "a"> = Vec::new();
+ let _: Cell<&str, "a"> = Cell::new("");
//~^ ERROR wrong number of generic arguments
}
error[E0107]: wrong number of generic arguments: expected 1, found 2
- --> $DIR/invalid-constant-in-args.rs:2:22
+ --> $DIR/invalid-constant-in-args.rs:4:23
|
-LL | let _: Vec<&str, "a"> = Vec::new();
- | ^^^ unexpected const argument
+LL | let _: Cell<&str, "a"> = Cell::new("");
+ | ^^^ unexpected const argument
error: aborting due to previous error
| ^^^^^ 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: generic parameters may not be used in const operations
--> $DIR/issue-61522-array-len-succ.rs:12:30
| ^^^^^ 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 2 previous errors
| ^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^ 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[E0392]: parameter `T` is never used
--> $DIR/issue-67375.rs:7:12
| ^ 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: generic parameters may not be used in const operations
--> $DIR/issue-67945-1.rs:17:45
| ^ 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:11:12
| ^ 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: generic parameters may not be used in const operations
--> $DIR/issue-67945-2.rs:15:45
| ^ 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-2.rs:9:12
| ^ cannot perform const operation using `C`
|
= help: const parameters may only be used as standalone arguments, i.e. `C`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 2 previous errors
| ^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^ 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: generic parameters may not be used in const operations
--> $DIR/issue-64494.rs:19:38
| ^^^^^^ 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[E0119]: conflicting implementations of trait `MyTrait`:
--> $DIR/issue-64494.rs:19:1
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^^^^^^^^ cannot perform const operation using `INT_BITS`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^^^^^^^^^ cannot perform const operation using `FRAC_BITS`
|
= help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 2 previous errors
| ^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 2 previous errors
| ^^^ cannot perform const operation using `LHS`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^^^ cannot perform const operation using `RHS`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `I`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `J`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to previous error
| ^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 2 previous errors
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 5 previous errors
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^ 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: generic parameters may not be used in const operations
--> $DIR/issue-76701-ty-param-in-const.rs:12:42
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 2 previous errors
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:34:17
+ --> $DIR/macro_rules-braces.rs:49:17
|
-LL | let _: baz!(N);
- | ^
+LL | let _: baz!(m::P);
+ | ^^^^
|
help: enclose the `const` expression in braces
|
-LL | let _: baz!({ N });
- | ^ ^
+LL | let _: baz!({ m::P });
+ | ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:54:17
+ --> $DIR/macro_rules-braces.rs:69:17
|
LL | let _: baz!(10 + 7);
| ^^^^^^
| ^ ^
error: constant expression depends on a generic parameter
- --> $DIR/macro_rules-braces.rs:10:13
+ --> $DIR/macro_rules-braces.rs:16: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:15:13
+ --> $DIR/macro_rules-braces.rs:21: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:20:13
+ --> $DIR/macro_rules-braces.rs:26: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:25:13
+ --> $DIR/macro_rules-braces.rs:31:13
|
LL | Foo<{ $x }>
| ^^^^^^^^^^^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:34:17
+ --> $DIR/macro_rules-braces.rs:49:17
|
-LL | let _: baz!(N);
- | ^
+LL | let _: baz!(m::P);
+ | ^^^^
|
help: enclose the `const` expression in braces
|
-LL | let _: baz!({ N });
- | ^ ^
+LL | let _: baz!({ m::P });
+ | ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/macro_rules-braces.rs:54:17
+ --> $DIR/macro_rules-braces.rs:69:17
|
LL | let _: baz!(10 + 7);
| ^^^^^^
| ^ ^
error: generic parameters may not be used in const operations
- --> $DIR/macro_rules-braces.rs:31:20
+ --> $DIR/macro_rules-braces.rs:37:20
|
LL | let _: foo!({{ N }});
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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:33:19
+ --> $DIR/macro_rules-braces.rs:41:19
|
LL | let _: bar!({ N });
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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:36:20
+ --> $DIR/macro_rules-braces.rs:46:20
|
LL | let _: baz!({{ N }});
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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:38:19
+ --> $DIR/macro_rules-braces.rs:51:19
|
LL | let _: biz!({ N });
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 6 previous errors
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(min, feature(min_const_generics))]
+mod m {
+ pub const P: usize = 0;
+}
+
+const Q: usize = 0;
+
fn test<const N: usize>() {
struct Foo<const M: usize>;
macro_rules! foo {
let _: foo!(N);
let _: foo!({ N });
let _: foo!({{ N }}); //[min]~ ERROR generic parameters may not
+ let _: foo!(Q);
+ let _: foo!(m::P);
let _: bar!(N);
let _: bar!({ N }); //[min]~ ERROR generic parameters may not
- let _: baz!(N); //~ ERROR expressions must be enclosed in braces
+ let _: bar!(Q);
+ let _: bar!(m::P);
+ let _: baz!(N);
let _: baz!({ N });
let _: baz!({{ N }}); //[min]~ ERROR generic parameters may not
+ let _: baz!(Q);
+ let _: baz!({ m::P });
+ let _: baz!(m::P); //~ ERROR expressions must be enclosed in braces
let _: biz!(N);
let _: biz!({ N }); //[min]~ ERROR generic parameters may not
+ let _: biz!(Q);
+ let _: biz!(m::P);
let _: foo!(3);
let _: foo!({ 3 });
let _: foo!({{ 3 }});
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ 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: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:30:47
| ^ 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: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:34:32
| ^ 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
warning: cannot use constants which depend on generic parameters in types
--> $DIR/complex-expression.rs:39:17
| ^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 7 previous errors
fn make_marker() -> impl Marker<{
#[macro_export]
- macro_rules! const_macro { () => {{ 3 }} }; inline!()
+ macro_rules! const_macro { () => {{ 3 }} } inline!()
}> {
Example::<{ const_macro!() }>
}
fn from_marker(_: impl Marker<{
#[macro_export]
- macro_rules! inline { () => {{ 3 }} }; inline!()
+ macro_rules! inline { () => {{ 3 }} } inline!()
}>) {}
fn main() {
#[macro_export]
macro_rules! gimme_a_const {
($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
- };
+ }
gimme_a_const!(run)
}>;
let _ok: [u8; {
#[macro_export]
- macro_rules! const_two { () => {{ 2 }} };
+ macro_rules! const_two { () => {{ 2 }} }
const_two!()
}];
let _ok = [0; {
#[macro_export]
- macro_rules! const_three { () => {{ 3 }} };
+ macro_rules! const_three { () => {{ 3 }} }
const_three!()
}];
let _ok = [0; const_three!()];
| ^^^^ cannot perform const operation using `Self`
|
= 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: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/self-ty-in-const-1.rs:14:41
| ^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| ^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to previous error
| |__^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^ 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: 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
| ^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 2 previous errors
| ^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 2 previous errors
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 6 previous errors
| ^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = 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
| ^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
- = note: more complex types are supported with `#[feature(const_generics)]`
+ = help: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 2 previous errors
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `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
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: aborting due to 2 previous errors
// run-pass
-#![feature(const_int_pow)]
#![feature(wrapping_next_power_of_two)]
const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two();
--- /dev/null
+// check-pass
+
+// Verify that variant count intrinsic can still evaluate for types like `Option<T>`.
+
+#![feature(variant_count)]
+
+pub struct GetVariantCount<T>(T);
+
+impl<T> GetVariantCount<T> {
+ pub const VALUE: usize = std::mem::variant_count::<T>();
+}
+
+const fn check_variant_count<T>() -> bool {
+ matches!(GetVariantCount::<Option<T>>::VALUE, GetVariantCount::<Option<()>>::VALUE)
+}
+
+fn main() {
+ assert!(check_variant_count::<()>());
+}
--- /dev/null
+// Test that `variant_count` only gets evaluated once the type is concrete enough.
+
+#![feature(variant_count)]
+
+pub struct GetVariantCount<T>(T);
+
+impl<T> GetVariantCount<T> {
+ pub const VALUE: usize = std::mem::variant_count::<T>();
+}
+
+const fn check_variant_count<T>() -> bool {
+ matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
+ //~^ ERROR constant pattern depends on a generic parameter
+ //~| ERROR constant pattern depends on a generic parameter
+}
+
+fn main() {
+ assert!(check_variant_count::<Option<()>>());
+}
--- /dev/null
+error: constant pattern depends on a generic parameter
+ --> $DIR/issue-79137-toogeneric.rs:12:43
+ |
+LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: constant pattern depends on a generic parameter
+ --> $DIR/issue-79137-toogeneric.rs:12:43
+ |
+LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// check-pass
+// Regression test for issue #79152
+//
+// Tests that we can index an array in a const function
+
+const fn foo() {
+ let mut array = [[0; 1]; 1];
+ array[0][0] = 1;
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+
+use std::net::{IpAddr, Ipv4Addr};
+
+fn main() {
+ const IP_ADDRESS : IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
+
+ const IS_IP_V4 : bool = IP_ADDRESS.is_ipv4();
+ assert!(IS_IP_V4);
+
+ const IS_IP_V6 : bool = IP_ADDRESS.is_ipv6();
+ assert!(!IS_IP_V6);
+}
#![allow(deprecated)]
#![allow(unused_imports)]
// compile-flags:--test
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-vxworks no 'cat' and 'sleep'
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
--- /dev/null
+// run-pass
+
+//! Test that let bindings and destructuring assignments have consistent drop orders
+
+#![feature(destructuring_assignment)]
+#![allow(unused_variables, unused_assignments)]
+
+use std::cell::RefCell;
+
+thread_local! {
+ static DROP_ORDER: RefCell<Vec<usize>> = RefCell::new(Vec::new());
+}
+
+struct DropRecorder(usize);
+impl Drop for DropRecorder {
+ fn drop(&mut self) {
+ DROP_ORDER.with(|d| d.borrow_mut().push(self.0));
+ }
+}
+
+fn main() {
+ let expected_drop_order = vec![1, 4, 5, 3, 2];
+ // Check the drop order for let bindings:
+ {
+ let _ = DropRecorder(1);
+ let _val = DropRecorder(2);
+ let (x, _) = (DropRecorder(3), DropRecorder(4));
+ drop(DropRecorder(5));
+ }
+ DROP_ORDER.with(|d| {
+ assert_eq!(&*d.borrow(), &expected_drop_order);
+ d.borrow_mut().clear();
+ });
+ // Check that the drop order for destructuring assignment is the same:
+ {
+ let _val;
+ let x;
+ _ = DropRecorder(1);
+ _val = DropRecorder(2);
+ (x, _) = (DropRecorder(3), DropRecorder(4));
+ drop(DropRecorder(5));
+ }
+ DROP_ORDER.with(|d| assert_eq!(&*d.borrow(), &expected_drop_order));
+}
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-android
// ignore-windows
-// ignore-cloudabi no execve
// ignore-emscripten no execve
// ignore-sgx no execve
// ignore-vxworks no execve
#![allow(unused_variables)]
#![allow(deprecated)]
-// ignore-cloudabi no environment variables present
// ignore-emscripten env vars don't work?
// ignore-sgx env vars cannot be modified
// run-pass
-// ignore-cloudabi no env vars
// ignore-wasm32-bare no env vars
use std::env::*;
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`)
= note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<T>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<T>>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<T>>>`
- = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<T>>`
+ = note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `Bar<T>`
error: aborting due to previous error
-// ignore-cloudabi no std::path
-
use std::path::Path;
trait Foo {
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
- --> $DIR/E0277.rs:13:6
+ --> $DIR/E0277.rs:11:6
|
LL | fn f(p: Path) { }
| ^ doesn't have a size known at compile-time
| ^
error[E0277]: the trait bound `i32: Foo` is not satisfied
- --> $DIR/E0277.rs:17:15
+ --> $DIR/E0277.rs:15:15
|
LL | fn some_func<T: Foo>(foo: T) {
| --- required by this bound in `some_func`
// run-pass
// exec-env:TEST_EXEC_ENV=22
-// ignore-cloudabi no env vars
// ignore-emscripten FIXME: issue #31622
// ignore-sgx unsupported
--- /dev/null
+// Test evaluation order of operands of the compound assignment operators
+
+// run-pass
+
+use std::ops::AddAssign;
+
+enum Side {
+ Lhs,
+ Rhs,
+}
+
+// In the following tests, we place our value into a wrapper type so that we
+// can do an element access as the outer place expression. If we just had the
+// block expression, it'd be a value expression and not compile.
+struct Wrapper<T>(T);
+
+// Evaluation order for `a op= b` where typeof(a) and typeof(b) are primitives
+// is first `b` then `a`.
+fn primitive_compound() {
+ let mut side_order = vec![];
+ let mut int = Wrapper(0);
+
+ {
+ side_order.push(Side::Lhs);
+ int
+ }.0 += {
+ side_order.push(Side::Rhs);
+ 0
+ };
+
+ assert!(matches!(side_order[..], [Side::Rhs, Side::Lhs]));
+}
+
+// Evaluation order for `a op=b` otherwise is first `a` then `b`.
+fn generic_compound<T: AddAssign<T> + Default>() {
+ let mut side_order = vec![];
+ let mut add_assignable: Wrapper<T> = Wrapper(Default::default());
+
+ {
+ side_order.push(Side::Lhs);
+ add_assignable
+ }.0 += {
+ side_order.push(Side::Rhs);
+ Default::default()
+ };
+
+ assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
+}
+
+fn custom_compound() {
+ struct Custom;
+
+ impl AddAssign<()> for Custom {
+ fn add_assign(&mut self, _: ()) {
+ // this block purposely left blank
+ }
+ }
+
+ let mut side_order = vec![];
+ let mut custom = Wrapper(Custom);
+
+ {
+ side_order.push(Side::Lhs);
+ custom
+ }.0 += {
+ side_order.push(Side::Rhs);
+ };
+
+ assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
+}
+
+fn main() {
+ primitive_compound();
+ generic_compound::<i32>();
+ custom_compound();
+}
// run-pass
// ignore-windows
// ignore-android
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-haiku
// ignore-sgx no processes
// The non-crate level cases are in issue-43106-gating-of-builtin-attrs.rs.
+#![allow(soft_unstable)]
#![test = "4200"]
//~^ ERROR cannot determine resolution for the attribute macro `test`
error: cannot determine resolution for the attribute macro `test`
- --> $DIR/issue-43106-gating-of-test.rs:3:4
+ --> $DIR/issue-43106-gating-of-test.rs:4:4
|
LL | #![test = "4200"]
| ^^^^
extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
//~^ ERROR intrinsic must be in
extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
-extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change
+extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change
extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental
extern "ptx-kernel" fn f6() {} //~ ERROR PTX ABIs are experimental and subject to change
extern "x86-interrupt" fn f7() {} //~ ERROR x86-interrupt ABI is experimental
extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
//~^ ERROR intrinsic must be in
extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
- extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change
+ extern "rust-call" fn m4(_: ()); //~ ERROR rust-call ABI is subject to change
extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental
extern "ptx-kernel" fn m6(); //~ ERROR PTX ABIs are experimental and subject to change
extern "x86-interrupt" fn m7(); //~ ERROR x86-interrupt ABI is experimental
extern "efiapi" fn m10(); //~ ERROR efiapi ABI is experimental and subject to change
extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
- extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change
+ extern "rust-call" fn dm4(_: ()) {} //~ ERROR rust-call ABI is subject to change
extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental
extern "ptx-kernel" fn dm6() {} //~ ERROR PTX ABIs are experimental and subject to change
extern "x86-interrupt" fn dm7() {} //~ ERROR x86-interrupt ABI is experimental
extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
//~^ ERROR intrinsic must be in
extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
- extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change
+ extern "rust-call" fn m4(_: ()) {} //~ ERROR rust-call ABI is subject to change
extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental
extern "ptx-kernel" fn m6() {} //~ ERROR PTX ABIs are experimental and subject to change
extern "x86-interrupt" fn m7() {} //~ ERROR x86-interrupt ABI is experimental
extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
//~^ ERROR intrinsic must be in
extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
- extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change
+ extern "rust-call" fn im4(_: ()) {} //~ ERROR rust-call ABI is subject to change
extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental
extern "ptx-kernel" fn im6() {} //~ ERROR PTX ABIs are experimental and subject to change
extern "x86-interrupt" fn im7() {} //~ ERROR x86-interrupt ABI is experimental
type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change
type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental
type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change
-type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change
+type A4 = extern "rust-call" fn(_: ()); //~ ERROR rust-call ABI is subject to change
type A5 = extern "msp430-interrupt" fn(); //~ ERROR msp430-interrupt ABI is experimental
type A6 = extern "ptx-kernel" fn (); //~ ERROR PTX ABIs are experimental and subject to change
type A7 = extern "x86-interrupt" fn(); //~ ERROR x86-interrupt ABI is experimental
error[E0658]: rust-call ABI is subject to change
--> $DIR/feature-gate-abi.rs:18:8
|
-LL | extern "rust-call" fn f4() {}
+LL | extern "rust-call" fn f4(_: ()) {}
| ^^^^^^^^^^^
|
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
error[E0658]: rust-call ABI is subject to change
--> $DIR/feature-gate-abi.rs:33:12
|
-LL | extern "rust-call" fn m4();
+LL | extern "rust-call" fn m4(_: ());
| ^^^^^^^^^^^
|
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
error[E0658]: rust-call ABI is subject to change
--> $DIR/feature-gate-abi.rs:42:12
|
-LL | extern "rust-call" fn dm4() {}
+LL | extern "rust-call" fn dm4(_: ()) {}
| ^^^^^^^^^^^
|
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
error[E0658]: rust-call ABI is subject to change
--> $DIR/feature-gate-abi.rs:60:12
|
-LL | extern "rust-call" fn m4() {}
+LL | extern "rust-call" fn m4(_: ()) {}
| ^^^^^^^^^^^
|
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
error[E0658]: rust-call ABI is subject to change
--> $DIR/feature-gate-abi.rs:76:12
|
-LL | extern "rust-call" fn im4() {}
+LL | extern "rust-call" fn im4(_: ()) {}
| ^^^^^^^^^^^
|
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
error[E0658]: rust-call ABI is subject to change
--> $DIR/feature-gate-abi.rs:89:18
|
-LL | type A4 = extern "rust-call" fn();
+LL | type A4 = extern "rust-call" fn(_: ());
| ^^^^^^^^^^^
|
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
--- /dev/null
+// Test that default and negative trait implementations are gated by
+// `auto_traits` feature gate
+
+struct DummyStruct;
+
+auto trait AutoDummyTrait {}
+//~^ ERROR auto traits are experimental and possibly buggy
+
+impl !AutoDummyTrait for DummyStruct {}
+//~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now
+
+fn main() {}
--- /dev/null
+error[E0658]: auto traits are experimental and possibly buggy
+ --> $DIR/feature-gate-auto-traits.rs:6:1
+ |
+LL | auto trait AutoDummyTrait {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information
+ = help: add `#![feature(auto_traits)]` to the crate attributes to enable
+
+error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now
+ --> $DIR/feature-gate-auto-traits.rs:9:6
+ |
+LL | impl !AutoDummyTrait for DummyStruct {}
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information
+ = help: add `#![feature(negative_impls)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
-error: cannot find attribute `lt_hof` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:51:21
+error: cannot find attribute `lt_struct` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:4:15
|
-LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
- | ^^^^^^
+LL | struct StLt<#[lt_struct] 'a>(&'a u32);
+ | ^^^^^^^^^
-error: cannot find attribute `ty_meth` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:46:15
+error: cannot find attribute `ty_struct` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:6:15
|
-LL | fn m_ty<#[ty_meth] P>(_: P) { }
- | ^^^^^^^
+LL | struct StTy<#[ty_struct] I>(I);
+ | ^^^^^^^^^
-error: cannot find attribute `lt_meth` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:44:15
+error: cannot find attribute `lt_enum` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:9:13
|
-LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
- | ^^^^^^^
+LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
+ | ^^^^^^^
-error: cannot find attribute `ty_fn` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:40:11
+error: cannot find attribute `ty_enum` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:11:13
|
-LL | fn f_ty<#[ty_fn] O>(_: O) { }
- | ^^^^^
+LL | enum EnTy<#[ty_enum] J> { A(J), B }
+ | ^^^^^^^
-error: cannot find attribute `lt_fn` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:38:11
+error: cannot find attribute `lt_trait` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:14:14
|
-LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
- | ^^^^^
+LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
+ | ^^^^^^^^
-error: cannot find attribute `ty_impl_for` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:33:8
+error: cannot find attribute `ty_trait` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:16:14
|
-LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
- | ^^^^^^^^^^^
+LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
+ | ^^^^^^^^
-error: cannot find attribute `lt_impl_for` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:29:8
+error: cannot find attribute `lt_type` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:19:13
|
-LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
- | ^^^^^^^^^^^
+LL | type TyLt<#[lt_type] 'd> = &'d u32;
+ | ^^^^^^^
-error: cannot find attribute `ty_inherent` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:26:8
+error: cannot find attribute `ty_type` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:21:13
|
-LL | impl<#[ty_inherent] M> StTy<M> { }
- | ^^^^^^^^^^^
+LL | type TyTy<#[ty_type] L> = (L, );
+ | ^^^^^^^
error: cannot find attribute `lt_inherent` in this scope
--> $DIR/feature-gate-custom_attribute2.rs:24:8
LL | impl<#[lt_inherent] 'e> StLt<'e> { }
| ^^^^^^^^^^^
-error: cannot find attribute `ty_type` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:21:13
+error: cannot find attribute `ty_inherent` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:26:8
|
-LL | type TyTy<#[ty_type] L> = (L, );
- | ^^^^^^^
+LL | impl<#[ty_inherent] M> StTy<M> { }
+ | ^^^^^^^^^^^
-error: cannot find attribute `lt_type` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:19:13
+error: cannot find attribute `lt_impl_for` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:29:8
|
-LL | type TyLt<#[lt_type] 'd> = &'d u32;
- | ^^^^^^^
+LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
+ | ^^^^^^^^^^^
-error: cannot find attribute `ty_trait` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:16:14
+error: cannot find attribute `ty_impl_for` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:33:8
|
-LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
- | ^^^^^^^^
+LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
+ | ^^^^^^^^^^^
-error: cannot find attribute `lt_trait` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:14:14
+error: cannot find attribute `lt_fn` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:38:11
|
-LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
- | ^^^^^^^^
+LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
+ | ^^^^^
-error: cannot find attribute `ty_enum` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:11:13
+error: cannot find attribute `ty_fn` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:40:11
|
-LL | enum EnTy<#[ty_enum] J> { A(J), B }
- | ^^^^^^^
+LL | fn f_ty<#[ty_fn] O>(_: O) { }
+ | ^^^^^
-error: cannot find attribute `lt_enum` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:9:13
+error: cannot find attribute `lt_meth` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:44:15
|
-LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
- | ^^^^^^^
+LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
+ | ^^^^^^^
-error: cannot find attribute `ty_struct` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:6:15
+error: cannot find attribute `ty_meth` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:46:15
|
-LL | struct StTy<#[ty_struct] I>(I);
- | ^^^^^^^^^
+LL | fn m_ty<#[ty_meth] P>(_: P) { }
+ | ^^^^^^^
-error: cannot find attribute `lt_struct` in this scope
- --> $DIR/feature-gate-custom_attribute2.rs:4:15
+error: cannot find attribute `lt_hof` in this scope
+ --> $DIR/feature-gate-custom_attribute2.rs:51:21
|
-LL | struct StLt<#[lt_struct] 'a>(&'a u32);
- | ^^^^^^^^^
+LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
+ | ^^^^^^
error: aborting due to 17 previous errors
+++ /dev/null
-// Test that default and negative trait implementations are gated by
-// `optin_builtin_traits` feature gate
-
-struct DummyStruct;
-
-auto trait AutoDummyTrait {}
-//~^ ERROR auto traits are experimental and possibly buggy
-
-impl !AutoDummyTrait for DummyStruct {}
-//~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now
-
-fn main() {}
+++ /dev/null
-error[E0658]: auto traits are experimental and possibly buggy
- --> $DIR/feature-gate-optin-builtin-traits.rs:6:1
- |
-LL | auto trait AutoDummyTrait {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information
- = help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable
-
-error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now
- --> $DIR/feature-gate-optin-builtin-traits.rs:9:6
- |
-LL | impl !AutoDummyTrait for DummyStruct {}
- | ^^^^^^^^^^^^^^^
- |
- = note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information
- = help: add `#![feature(negative_impls)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
-#![feature(exclusive_range_pattern)]
-
-use std::usize::MAX;
+use std::{isize, usize};
fn main() {
- match 0usize { //~ERROR non-exhaustive patterns: `_` not covered
- 0..=MAX => {}
+ match 0usize {
+ //~^ ERROR non-exhaustive patterns: `_` not covered
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `usize`
+ //~| NOTE `usize` does not have a fixed maximum value
+ 0..=usize::MAX => {}
}
- match 0isize { //~ERROR non-exhaustive patterns: `_` not covered
- 1..=20 => {}
- -5..3 => {}
+ match 0isize {
+ //~^ ERROR non-exhaustive patterns: `_` not covered
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `isize`
+ //~| NOTE `isize` does not have a fixed maximum value
+ isize::MIN..=isize::MAX => {}
}
}
error[E0004]: non-exhaustive patterns: `_` not covered
- --> $DIR/feature-gate-precise_pointer_size_matching.rs:6:11
+ --> $DIR/feature-gate-precise_pointer_size_matching.rs:4:11
|
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
- --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
+ --> $DIR/feature-gate-precise_pointer_size_matching.rs:12:11
|
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
// RFC #2795 suggests that this may need to change so that captured arguments are formatted.
// For stability reasons this will need to part of an edition change.
+ #[allow(panic_fmt)]
let msg = std::panic::catch_unwind(|| {
panic!("{foo}");
}).unwrap_err();
#![feature(generators)]
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait Foo {}
--- /dev/null
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+trait X {
+ type Y<'a>;
+}
+
+fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
+ //~^ ERROR: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+
+fn main() {}
--- /dev/null
+error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+ --> $DIR/trait-path-expected-token.rs:8:33
+ |
+LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
+ | ^ expected one of 7 possible tokens
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/trait-path-expected-token.rs:1:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+mod error1 {
+ trait X {
+ type Y<'a>;
+ }
+
+ fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
+ //~^ ERROR: expected expression, found `)`
+}
+
+mod error2 {
+
+ trait X {
+ type Y<'a>;
+ }
+
+ fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
+ //~^ ERROR: only types can be used in associated type constraints
+}
+
+fn main() {}
--- /dev/null
+error: expected expression, found `)`
+ --> $DIR/trait-path-expressions.rs:9:39
+ |
+LL | fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
+ | - ^ expected expression
+ | |
+ | while parsing a const generic argument starting here
+
+error: only types can be used in associated type constraints
+ --> $DIR/trait-path-expressions.rs:19:30
+ |
+LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
+ | ^^^^^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/trait-path-expressions.rs:1:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
--- /dev/null
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+trait X {
+ type Y<'a>;
+}
+
+const _: () = {
+ fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+ //~^ ERROR: expected one of `>`, const, lifetime, or type, found `:`
+ //~| ERROR: expected parameter name, found `>`
+ //~| ERROR: expected one of `!`, `)`, `+`, `,`, or `::`, found `>`
+ //~| ERROR: constant provided when a type was expected
+};
+
+const _: () = {
+ fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
+ //~^ ERROR: expected one of `>`, const, lifetime, or type, found `=`
+};
+
+fn main() {}
--- /dev/null
+error: expected one of `>`, const, lifetime, or type, found `:`
+ --> $DIR/trait-path-missing-gen_arg.rs:9:30
+ |
+LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+ | ^ expected one of `>`, const, lifetime, or type
+ |
+help: expressions must be enclosed in braces to be used as const generic arguments
+ |
+LL | fn f1<'a>(arg : Box<{ dyn X< : 32 } >>) {}
+ | ^ ^
+
+error: expected parameter name, found `>`
+ --> $DIR/trait-path-missing-gen_arg.rs:9:36
+ |
+LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+ | ^ expected parameter name
+
+error: expected one of `!`, `)`, `+`, `,`, or `::`, found `>`
+ --> $DIR/trait-path-missing-gen_arg.rs:9:36
+ |
+LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+ | ^
+ | |
+ | expected one of `!`, `)`, `+`, `,`, or `::`
+ | help: missing `,`
+
+error: expected one of `>`, const, lifetime, or type, found `=`
+ --> $DIR/trait-path-missing-gen_arg.rs:17:30
+ |
+LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
+ | ^ expected one of `>`, const, lifetime, or type
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/trait-path-missing-gen_arg.rs:1:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0747]: constant provided when a type was expected
+ --> $DIR/trait-path-missing-gen_arg.rs:9:23
+ |
+LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+ | ^^^^^^^^^^^
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0747`.
--- /dev/null
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+const _: () = {
+ trait X {
+ type Y<'a>;
+ }
+
+ fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
+ //~^ ERROR: paths with multiple segments cannot be used in associated type constraints
+ };
+
+const _: () = {
+ trait X {
+ type Y<'a>;
+ }
+
+ trait Z {}
+
+ impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
+ //~^ ERROR: qualified paths cannot be used in associated type constraints
+};
+
+const _: () = {
+ trait X {
+ type Y<'a>;
+ }
+
+ trait Z {}
+
+ impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
+ //~^ ERROR: paths with multiple segments cannot be used in associated type constraints
+};
+
+fn main() {}
--- /dev/null
+error: paths with multiple segments cannot be used in associated type constraints
+ --> $DIR/trait-path-segments.rs:9:31
+ |
+LL | fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
+ | ^^^^
+
+error: qualified paths cannot be used in associated type constraints
+ --> $DIR/trait-path-segments.rs:20:16
+ |
+LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
+ | ^^^^^^^^^-^^^^^^^^
+ | |
+ | not allowed in associated type constraints
+
+error: paths with multiple segments cannot be used in associated type constraints
+ --> $DIR/trait-path-segments.rs:31:16
+ |
+LL | impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
+ | ^^^^^^^^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/trait-path-segments.rs:1:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
--- /dev/null
+#![feature(generic_associated_types)]
+
+trait X {
+ type Y<'a>;
+}
+
+const _: () = {
+ fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
+ //~^ ERROR: generic associated types in trait paths are currently not implemented
+};
--- /dev/null
+error: generic associated types in trait paths are currently not implemented
+ --> $DIR/trait-path-type-error-once-implemented.rs:8:30
+ |
+LL | fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
+ | ^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+trait X {
+ type Y<'a>;
+}
+
+const _: () = {
+ fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
+ //~^ ERROR: only path types can be used in associated type constraints
+};
+
+const _: () = {
+ fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
+ //~^ ERROR: only path types can be used in associated type constraints
+};
+
+const _: () = {
+ fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
+ //~^ ERROR: only types can be used in associated type constraints
+};
+
+fn main() {}
--- /dev/null
+error: only path types can be used in associated type constraints
+ --> $DIR/trait-path-types.rs:9:29
+ |
+LL | fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
+ | ^^^^^^^
+
+error: only path types can be used in associated type constraints
+ --> $DIR/trait-path-types.rs:14:29
+ |
+LL | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
+ | ^^^^^^^
+
+error: only types can be used in associated type constraints
+ --> $DIR/trait-path-types.rs:19:30
+ |
+LL | fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
+ | ^^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/trait-path-types.rs:1:12
+ |
+LL | #![feature(generic_associated_types)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
--- /dev/null
+#![feature(generic_associated_types)]
+
+trait X {
+ type Y<'a>;
+}
+
+const _: () = {
+ fn f1<'a>(arg : Box<dyn X<Y<'a> = &'a ()>>) {}
+ //~^ ERROR: generic associated types in trait paths are currently not implemented
+};
+
+const _: () = {
+ fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}
+ //~^ ERROR: lifetime in trait object type must be followed by `+`
+};
+
+fn main() {}
--- /dev/null
+error: lifetime in trait object type must be followed by `+`
+ --> $DIR/trait-path-unimplemented.rs:13:31
+ |
+LL | fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}
+ | ^^
+
+error: generic associated types in trait paths are currently not implemented
+ --> $DIR/trait-path-unimplemented.rs:8:30
+ |
+LL | fn f1<'a>(arg : Box<dyn X<Y<'a> = &'a ()>>) {}
+ | ^^^^
+
+error: aborting due to 2 previous errors
+
#![feature(decl_macro)]
mod foo {
- pub macro m() { Vec::new(); ().clone() }
+ pub macro m() { Vec::<i32>::new(); ().clone() }
fn f() { ::bar::m!(); }
}
}
fn f() {
::foo::m!();
- assert_eq!(0, 0); //~ ERROR cannot find macro `panic` in this scope
+ assert!(true);
}
}
-error: cannot find macro `panic` in this scope
- --> $DIR/no_implicit_prelude.rs:16:9
- |
-LL | assert_eq!(0, 0);
- | ^^^^^^^^^^^^^^^^^
- |
- = note: consider importing one of these items:
- core::panic
- std::panic
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
error[E0433]: failed to resolve: use of undeclared type `Vec`
--> $DIR/no_implicit_prelude.rs:11:9
|
`use std::clone::Clone;`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0433, E0599.
For more information about an error, try `rustc --explain E0433`.
--- /dev/null
+// edition:2018
+
+#![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
+
+struct Bug {
+ V1: [(); {
+ let f: impl core::future::Future<Output = u8> = async { 1 };
+ //~^ ERROR `async` blocks are not allowed in constants
+ //~| ERROR destructors cannot be evaluated at compile-time
+ 1
+ }],
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-78721.rs:3:12
+ |
+LL | #![feature(impl_trait_in_bindings)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+
+error: `async` blocks are not allowed in constants
+ --> $DIR/issue-78721.rs:8:57
+ |
+LL | let f: impl core::future::Future<Output = u8> = async { 1 };
+ | ^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/issue-78721.rs:8:13
+ |
+LL | let f: impl core::future::Future<Output = u8> = async { 1 };
+ | ^ constants cannot evaluate destructors
+...
+LL | }],
+ | - value is dropped here
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0493`.
--- /dev/null
+// edition:2018
+
+#![feature(type_alias_impl_trait)]
+#![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
+
+type F = impl core::future::Future<Output = u8>;
+
+struct Bug {
+ V1: [(); {
+ fn concrete_use() -> F {
+ async {}
+ }
+ let f: F = async { 1 };
+ //~^ ERROR `async` blocks are not allowed in constants
+ //~| ERROR destructors cannot be evaluated at compile-time
+ 1
+ }],
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-78722.rs:4:12
+ |
+LL | #![feature(impl_trait_in_bindings)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+
+error: `async` blocks are not allowed in constants
+ --> $DIR/issue-78722.rs:14:20
+ |
+LL | let f: F = async { 1 };
+ | ^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/issue-78722.rs:14:13
+ |
+LL | let f: F = async { 1 };
+ | ^ constants cannot evaluate destructors
+...
+LL | }],
+ | - value is dropped here
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0493`.
}
#[cfg(any(target_os = "android",
- target_os = "cloudabi",
target_os = "dragonfly",
target_os = "emscripten",
target_os = "freebsd",
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
pub fn main() {
fn f() {
- };
+ }
let _: Box<fn()> = box (f as fn());
}
+++ /dev/null
-#![feature(box_patterns)]
-#![feature(box_syntax)]
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![deny(unreachable_patterns)]
-
-enum IntList {
- Cons(isize, Box<IntList>),
- Nil
-}
-
-fn tail(source_list: &IntList) -> IntList {
- match source_list {
- &IntList::Cons(val, box ref next_list) => tail(next_list),
- &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil),
-//~^ ERROR unreachable pattern
- _ => panic!()
- }
-}
-
-fn main() {}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/issue-12116.rs:15:9
- |
-LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/issue-12116.rs:5:9
- |
-LL | #![deny(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
// aux-build:issue-12133-rlib.rs
// aux-build:issue-12133-dylib.rs
// aux-build:issue-12133-dylib2.rs
-// ignore-cloudabi no dylib support
// ignore-emscripten no dylib support
// ignore-musl
// ignore-sgx no dylib support
+++ /dev/null
-#![deny(unreachable_patterns)]
-
-fn main() {
- let sl = vec![1,2,3];
- let v: isize = match &*sl {
- &[] => 0,
- &[a,b,c] => 3,
- &[a, ref rest @ ..] => a,
- &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern
- };
-}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/issue-12369.rs:9:9
- |
-LL | &[10,a, ref rest @ ..] => 10
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/issue-12369.rs:1:9
- |
-LL | #![deny(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
// run-pass
#![allow(unused_mut)]
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
+++ /dev/null
-#![allow(overflowing_literals)]
-#![deny(unreachable_patterns)]
-
-fn test(val: u8) {
- match val {
- 256 => print!("0b1110\n"),
- 512 => print!("0b1111\n"),
- //~^ ERROR: unreachable pattern
- _ => print!("fail\n"),
- }
-}
-
-fn main() {
- test(1);
-}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/issue-13727.rs:7:5
- |
-LL | 512 => print!("0b1111\n"),
- | ^^^
- |
-note: the lint level is defined here
- --> $DIR/issue-13727.rs:2:9
- |
-LL | #![deny(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
// run-pass
#![allow(unused_mut)]
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
+++ /dev/null
-pub enum T {
- T1(()),
- T2(())
-}
-
-pub enum V {
- V1(isize),
- V2(bool)
-}
-
-fn main() {
- match (T::T1(()), V::V2(true)) {
- //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered
- (T::T1(()), V::V1(i)) => (),
- (T::T2(()), V::V2(b)) => ()
- }
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered
- --> $DIR/issue-15129.rs:12:11
- |
-LL | match (T::T1(()), V::V2(true)) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `(T, V)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// check-pass
#![allow(dead_code)]
// pretty-expanded FIXME #23616
-// ignore-cloudabi no std::fs
use std::fs::File;
use std::io::{self, BufReader, Read};
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_18400`)
= note: required because of the requirements on the impl of `Set<&[_]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[_]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[_]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[_]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[_]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[_]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[_]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[_]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[_]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
- = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
+ = note: 128 redundant requirements hidden
= note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}`
error: aborting due to previous error
// run-pass
#![allow(stable_features)]
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
}
}
+trait Bar {
+ fn answer(self);
+}
+
+trait Baz {
+ fn answer(self);
+}
+
+struct AlmostNoData<T>(Option<T>);
+
+struct EvenLessData<T>(Option<T>);
+
+impl<T> Bar for T where EvenLessData<T>: Baz {
+//~^ ERROR: overflow evaluating the requirement
+//~| ERROR: overflow evaluating the requirement
+ fn answer(self) {
+ let val: EvenLessData<T> = EvenLessData(None);
+ }
+}
+
+impl<T> Baz for T where AlmostNoData<T>: Bar {
+//~^ ERROR: overflow evaluating the requirement
+//~| ERROR: overflow evaluating the requirement
+ fn answer(self) {
+ let val: NoData<T> = AlmostNoData(None);
+ }
+}
+
fn main() {}
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
= note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<T>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<T>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<T>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<T>>`
+ = note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `NoData<T>`
+error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz`
+ --> $DIR/issue-20413.rs:28:42
+ |
+LL | trait Baz {
+ | --------- required by this bound in `Baz`
+...
+LL | impl<T> Bar for T where EvenLessData<T>: Baz {
+ | ^^^
+ |
+ = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
+ = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: 126 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Baz` for `EvenLessData<T>`
+
+error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar`
+ --> $DIR/issue-20413.rs:36:42
+ |
+LL | trait Bar {
+ | --------- required by this bound in `Bar`
+...
+LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
+ | ^^^
+ |
+ = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
+ = note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: 126 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<T>`
+
error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/issue-20413.rs:8:36
|
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
= note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<T>>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<T>>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<T>>>`
- = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<T>>`
+ = note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `NoData<T>`
-error: aborting due to 3 previous errors
+error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz`
+ --> $DIR/issue-20413.rs:28:42
+ |
+LL | trait Baz {
+ | --------- required by this bound in `Baz`
+...
+LL | impl<T> Bar for T where EvenLessData<T>: Baz {
+ | ^^^
+ |
+ = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
+ = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: 126 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Baz` for `EvenLessData<T>`
+
+error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar`
+ --> $DIR/issue-20413.rs:36:42
+ |
+LL | trait Bar {
+ | --------- required by this bound in `Bar`
+...
+LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
+ | ^^^
+ |
+ = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`)
+ = note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+ = note: 126 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<T>`
+
+error: aborting due to 7 previous errors
Some errors have detailed explanations: E0275, E0392.
For more information about an error, try `rustc --explain E0275`.
|
::: $SRC_DIR/alloc/src/vec.rs:LL:COL
|
-LL | pub struct Vec<T> {
+LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global> {
| - required by this bound in `Vec`
|
= help: the trait `Sized` is not implemented for `[i32]`
//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(`
+type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,`, `:`, `=`, or `>`, found `(`
//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-error: expected one of `,` or `>`, found `(`
+error: expected one of `,`, `:`, `=`, or `>`, found `(`
--> $DIR/issue-20616-2.rs:12:31
|
LL | type Type_2 = Type_1_<'static ()>;
- | ^ expected one of `,` or `>`
+ | ^ expected one of `,`, `:`, `=`, or `>`
error: aborting due to previous error
type Type_3<T> = Box<T,,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
--> $DIR/issue-20616-3.rs:13:24
|
LL | type Type_3<T> = Box<T,,>;
- | ^ expected one of `>`, const, identifier, lifetime, or type
+ | ^ expected one of `>`, const, lifetime, or type
error: aborting due to previous error
type Type_4<T> = Type_1_<'static,, T>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
type Type_5_<'a> = Type_1_<'a, ()>;
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
--> $DIR/issue-20616-4.rs:16:34
|
LL | type Type_4<T> = Type_1_<'static,, T>;
- | ^ expected one of `>`, const, identifier, lifetime, or type
+ | ^ expected one of `>`, const, lifetime, or type
error: aborting due to previous error
type Type_5<'a> = Type_1_<'a, (),,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
--> $DIR/issue-20616-5.rs:22:34
|
LL | type Type_5<'a> = Type_1_<'a, (),,>;
- | ^ expected one of `>`, const, identifier, lifetime, or type
+ | ^ expected one of `>`, const, lifetime, or type
error: aborting due to previous error
type Type_6 = Type_5_<'a,,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
//type Type_7 = Box<(),,>; // error: expected type, found `,`
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
--> $DIR/issue-20616-6.rs:25:26
|
LL | type Type_6 = Type_5_<'a,,>;
- | ^ expected one of `>`, const, identifier, lifetime, or type
+ | ^ expected one of `>`, const, lifetime, or type
error: aborting due to previous error
type Type_7 = Box<(),,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
--> $DIR/issue-20616-7.rs:28:22
|
LL | type Type_7 = Box<(),,>;
- | ^ expected one of `>`, const, identifier, lifetime, or type
+ | ^ expected one of `>`, const, lifetime, or type
error: aborting due to previous error
// had to do with codegen ignoring binders.
// pretty-expanded FIXME #23616
-// ignore-cloudabi no std::fs
#![feature(os)]
pub fn main() {
let one = || {
- enum r { a };
+ enum r { a }
r::a as usize
};
let two = || {
- enum r { a };
+ enum r { a }
r::a as usize
};
one(); two();
// build-pass
-// ignore-cloudabi no std::fs
// Regression test for #20797.
+++ /dev/null
-fn foo(a: Option<usize>, b: Option<usize>) {
- match (a,b) {
- //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
- (Some(a), Some(b)) if a == b => { }
- (Some(_), None) |
- (None, Some(_)) => { }
- }
-}
-
-fn main() {
- foo(None, None);
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `(None, None)` not covered
- --> $DIR/issue-2111.rs:2:9
- |
-LL | match (a,b) {
- | ^^^^^ pattern `(None, None)` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `(Option<usize>, Option<usize>)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
use libc::{c_double, c_int};
extern {
- #[cfg(any(all(unix, not(target_os = "vxworks")), target_os = "cloudabi"))]
+ #[cfg(all(unix, not(target_os = "vxworks")))]
#[link_name="lgamma_r"]
pub fn lgamma(n: c_double, sign: &mut c_int) -> c_double;
#[cfg(windows)]
// run-pass
#![allow(dead_code)]
// pretty-expanded FIXME #23616
-// ignore-cloudabi no std::fs
use std::{fs, net};
// run-pass
-// ignore-cloudabi no std::path
use std::collections::HashMap;
use std::path::Path;
// run-pass
-// ignore-cloudabi no std::path
use std::collections::HashMap;
use std::path::{Path, PathBuf};
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no threads
// ignore-sgx no processes
// run-pass
-// ignore-cloudabi no std::env
// ignore-wasm32 issue 42629
#[inline(never)]
// compile-flags: --test
+#![allow(soft_unstable)]
#![test] //~ ERROR cannot determine resolution for the attribute macro `test`
error: cannot determine resolution for the attribute macro `test`
- --> $DIR/issue-28134.rs:3:4
+ --> $DIR/issue-28134.rs:4:4
|
LL | #![test]
| ^^^^
// check-pass
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait NotSame {}
+++ /dev/null
-#![deny(unreachable_patterns)]
-
-fn main() {
- match "world" {
- "hello" => {}
- _ => {},
- }
-
- match "world" {
- ref _x if false => {}
- "hello" => {}
- "hello" => {} //~ ERROR unreachable pattern
- _ => {},
- }
-}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/issue-30240-b.rs:12:9
- |
-LL | "hello" => {}
- | ^^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/issue-30240-b.rs:1:9
- |
-LL | #![deny(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-fn main() {
- let &ref a = &[0i32] as &[_];
- assert_eq!(a, &[0i32] as &[_]);
-
- let &ref a = "hello";
- assert_eq!(a, "hello");
-
- match "foo" {
- "fool" => unreachable!(),
- "foo" => {},
- ref _x => unreachable!()
- }
-}
+++ /dev/null
-fn main() {
- match "world" { //~ ERROR non-exhaustive patterns: `&_`
- "hello" => {}
- }
-
- match "world" { //~ ERROR non-exhaustive patterns: `&_`
- ref _x if false => {}
- "hello" => {}
- }
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `&_` not covered
- --> $DIR/issue-30240.rs:2:11
- |
-LL | match "world" {
- | ^^^^^^^ pattern `&_` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `&str`
-
-error[E0004]: non-exhaustive patterns: `&_` not covered
- --> $DIR/issue-30240.rs:6:11
- |
-LL | match "world" {
- | ^^^^^^^ pattern `&_` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `&str`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
+++ /dev/null
-fn main() {
- match () { } //~ ERROR non-exhaustive
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: type `()` is non-empty
- --> $DIR/issue-3096-1.rs:2:11
- |
-LL | match () { }
- | ^^
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `()`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
+++ /dev/null
-enum Bottom { }
-
-fn main() {
- let x = &() as *const () as *const Bottom;
- match x { } //~ ERROR non-exhaustive patterns
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty
- --> $DIR/issue-3096-2.rs:5:11
- |
-LL | match x { }
- | ^
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `*const Bottom`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
LL | .collect();
| ^^^^^^^ method not found in `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>`
|
- ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL
+ ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
|
LL | pub struct Cloned<I> {
| -------------------- doesn't satisfy `_: Iterator`
-...
+ |
+ ::: $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
+ |
LL | pub struct TakeWhile<I, P> {
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
|
+++ /dev/null
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![allow(non_snake_case)]
-#![deny(unreachable_patterns)]
-
-#[derive(Clone, Copy)]
-enum Enum {
- Var1,
- Var2,
-}
-
-fn main() {
- use Enum::*;
- let s = Var1;
- match s {
- Var1 => (),
- Var3 => (),
- Var2 => (),
- //~^ ERROR unreachable pattern
- };
- match &s {
- &Var1 => (),
- &Var3 => (),
- &Var2 => (),
- //~^ ERROR unreachable pattern
- };
- let t = (Var1, Var1);
- match t {
- (Var1, b) => (),
- (c, d) => (),
- anything => ()
- //~^ ERROR unreachable pattern
- };
-}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/issue-31221.rs:18:9
- |
-LL | Var3 => (),
- | ---- matches any value
-LL | Var2 => (),
- | ^^^^ unreachable pattern
- |
-note: the lint level is defined here
- --> $DIR/issue-31221.rs:4:9
- |
-LL | #![deny(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
- --> $DIR/issue-31221.rs:24:9
- |
-LL | &Var3 => (),
- | ----- matches any value
-LL | &Var2 => (),
- | ^^^^^ unreachable pattern
-
-error: unreachable pattern
- --> $DIR/issue-31221.rs:31:9
- |
-LL | (c, d) => (),
- | ------ matches any value
-LL | anything => ()
- | ^^^^^^^^ unreachable pattern
-
-error: aborting due to 3 previous errors
-
+++ /dev/null
-enum Thing {
- Foo(u8),
- Bar,
- Baz
-}
-
-fn main() {
- let Thing::Foo(y) = Thing::Foo(1);
- //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered
-}
+++ /dev/null
-error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
- --> $DIR/issue-31561.rs:8:9
- |
-LL | / enum Thing {
-LL | | Foo(u8),
-LL | | Bar,
- | | --- not covered
-LL | | Baz
- | | --- not covered
-LL | | }
- | |_- `Thing` defined here
-...
-LL | let Thing::Foo(y) = Thing::Foo(1);
- | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
- |
- = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
- = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
- = note: the matched value is of type `Thing`
-help: you might want to use `if let` to ignore the variant that isn't matched
- |
-LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ }
- |
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0005`.
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
fn main () {
let sr: Vec<(u32, _, _) = vec![];
- //~^ ERROR expected one of `,` or `>`, found `=`
+ //~^ ERROR only path types can be used in associated type constraints
let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
//~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built
}
-error: expected one of `,` or `>`, found `=`
- --> $DIR/issue-34334.rs:2:29
+error: only path types can be used in associated type constraints
+ --> $DIR/issue-34334.rs:2:17
|
LL | let sr: Vec<(u32, _, _) = vec![];
- | -- ^ expected one of `,` or `>`
+ | -- ^^^^^^^^^^^
| |
| while parsing the type for `sr`
+++ /dev/null
-#![feature(box_patterns)]
-#![feature(box_syntax)]
-
-struct HTMLImageData {
- image: Option<String>
-}
-
-struct ElementData {
- kind: Box<ElementKind>
-}
-
-enum ElementKind {
- HTMLImageElement(HTMLImageData)
-}
-
-enum NodeKind {
- Element(ElementData)
-}
-
-struct NodeData {
- kind: Box<NodeKind>,
-}
-
-fn main() {
- let mut id = HTMLImageData { image: None };
- let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) };
- let n = NodeData {kind : box NodeKind::Element(ed)};
- // n.b. span could be better
- match n.kind {
- box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
- box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
- },
- };
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `Box(_, _)` not covered
- --> $DIR/issue-3601.rs:30:44
- |
-LL | box NodeKind::Element(ed) => match ed.kind {
- | ^^^^^^^ pattern `Box(_, _)` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Box<ElementKind>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
#![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
//~| ERROR cannot determine resolution for the derive macro `Copy`
- //~| ERROR cannot determine resolution for the derive macro `Copy`
fn main() {}
|
= note: import resolution is stuck, try simplifying macro imports
-error: cannot determine resolution for the derive macro `Copy`
- --> $DIR/issue-36617.rs:1:11
- |
-LL | #![derive(Copy)]
- | ^^^^
- |
- = note: import resolution is stuck, try simplifying macro imports
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0774`.
// compile-flags: -Z unpretty=mir
-// ignore-cloudabi no std::path
use std::path::MAIN_SEPARATOR;
error[E0308]: mismatched types
- --> $DIR/issue-37665.rs:10:17
+ --> $DIR/issue-37665.rs:9:17
|
LL | let x: () = 0;
| -- ^ expected `()`, found integer
// these platforms also.
// ignore-windows
-// ignore-cloudabi
// ignore-emscripten
// ignore-sgx no processes
error[E0599]: no method named `exec` found for mutable reference `&mut Command` in the current scope
- --> $DIR/issue-39175.rs:15:39
+ --> $DIR/issue-39175.rs:14:39
|
LL | Command::new("echo").arg("hello").exec();
| ^^^^ method not found in `&mut Command`
+++ /dev/null
-enum Foo {
- Bar { bar: Bar, id: usize }
-}
-
-enum Bar {
- A, B, C, D, E, F
-}
-
-fn test(f: Foo) {
- match f {
- //~^ ERROR non-exhaustive patterns
- //~| patterns
- Foo::Bar { bar: Bar::A, .. } => (),
- Foo::Bar { bar: Bar::B, .. } => (),
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
- --> $DIR/issue-39362.rs:10:11
- |
-LL | / enum Foo {
-LL | | Bar { bar: Bar, id: usize }
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match f {
- | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Foo`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
-error: cannot find macro `m` in this scope
- --> $DIR/issue-40845.rs:4:10
- |
-LL | impl S { m!(); }
- | ^
-
error: cannot find macro `m` in this scope
--> $DIR/issue-40845.rs:1:11
|
LL | trait T { m!(); }
| ^
+error: cannot find macro `m` in this scope
+ --> $DIR/issue-40845.rs:4:10
+ |
+LL | impl S { m!(); }
+ | ^
+
error: aborting due to 2 previous errors
+++ /dev/null
-fn main() {
- let tup = (true, true);
- println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered
- (false, false) => "foo",
- (false, true) => "bar",
- (true, true) => "baz"
- });
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `(true, false)` not covered
- --> $DIR/issue-4321.rs:3:31
- |
-LL | println!("foo {:}", match tup {
- | ^^^ pattern `(true, false)` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `(bool, bool)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
// run-pass
-// ignore-cloudabi no std::env
fn parse_args() -> String {
let args: Vec<_> = ::std::env::args().collect();
// run-pass
// pretty-expanded FIXME #23616
-// ignore-cloudabi no std::env
use std::env;
-// ignore-cloudabi no std::fs support
-
#![allow(dead_code)]
#![deny(unused_imports)]
error: unused import: `BufRead`
- --> $DIR/issue-46576.rs:7:15
+ --> $DIR/issue-46576.rs:5:15
|
LL | use std::io::{BufRead, BufReader, Read};
| ^^^^^^^
|
note: the lint level is defined here
- --> $DIR/issue-46576.rs:4:9
+ --> $DIR/issue-46576.rs:2:9
|
LL | #![deny(unused_imports)]
| ^^^^^^^^^^^^^^
fn foo<#[derive(Debug)] T>() {
//~^ ERROR `derive` may only be applied to structs, enums and unions
-//~| ERROR expected an inert attribute, found a derive macro
match 0 {
#[derive(Debug)]
//~^ ERROR `derive` may only be applied to structs, enums and unions
- //~| ERROR expected an inert attribute, found a derive macro
_ => (),
}
}
LL | fn foo<#[derive(Debug)] T>() {
| ^^^^^^^^^^^^^^^^
-error: expected an inert attribute, found a derive macro
- --> $DIR/issue-49934-errors.rs:1:17
- |
-LL | fn foo<#[derive(Debug)] T>() {
- | ^^^^^
-
error[E0774]: `derive` may only be applied to structs, enums and unions
- --> $DIR/issue-49934-errors.rs:5:9
+ --> $DIR/issue-49934-errors.rs:4:9
|
LL | #[derive(Debug)]
| ^^^^^^^^^^^^^^^^
-error: expected an inert attribute, found a derive macro
- --> $DIR/issue-49934-errors.rs:5:18
- |
-LL | #[derive(Debug)]
- | ^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0774`.
+// revisions: default miropt
+//[miropt]compile-flags: -Z mir-opt-level=2
+// ~^ This flag is for #77668, it used to be ICE.
+
#![crate_type = "lib"]
pub fn bar<P>( // Error won't happen if "bar" is not generic
+++ /dev/null
-#![crate_type="lib"]
-#![deny(unreachable_patterns)]
-
-mod test_struct {
- // Test the exact copy of the minimal example
- // posted in the issue.
- pub struct Punned {
- foo: [u8; 1],
- bar: [u8; 1],
- }
-
- pub fn test(punned: Punned) {
- match punned {
- Punned { foo: [_], .. } => println!("foo"),
- Punned { bar: [_], .. } => println!("bar"),
- //~^ ERROR unreachable pattern [unreachable_patterns]
- }
- }
-}
-
-mod test_union {
- // Test the same thing using a union.
- pub union Punned {
- foo: [u8; 1],
- bar: [u8; 1],
- }
-
- pub fn test(punned: Punned) {
- match punned {
- Punned { foo: [_] } => println!("foo"),
- Punned { bar: [_] } => println!("bar"),
- //~^ ERROR unreachable pattern [unreachable_patterns]
- }
- }
-}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/issue-57472.rs:15:13
- |
-LL | Punned { bar: [_], .. } => println!("bar"),
- | ^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/issue-57472.rs:2:9
- |
-LL | #![deny(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
- --> $DIR/issue-57472.rs:31:13
- |
-LL | Punned { bar: [_] } => println!("bar"),
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
--- /dev/null
+// run-pass
+#![feature(const_evaluatable_checked)]
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait Foo {}
+
+impl<const N: usize> Foo for [(); N] where Self: FooImpl<{ N == 0 }> {}
+
+trait FooImpl<const IS_ZERO: bool> {}
+
+impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {}
+
+impl<const N: usize> FooImpl<{ 0u8 != 0u8 }> for [(); N] {}
+
+fn foo<T: Foo>(_v: T) {}
+
+fn main() {
+ foo([]);
+ foo([()]);
+}
// only-32bit too impatient for 2⁶⁴ items
// compile-flags: -C debug_assertions=no -C opt-level=3
-use std::panic;
use std::usize::MAX;
fn main() {
// only-32bit too impatient for 2⁶⁴ items
// compile-flags: -C debug_assertions=no -C opt-level=3
-use std::panic;
use std::usize::MAX;
fn main() {
-error[E0518]: attribute should be applied to function or closure
- --> $DIR/inline-trait-and-foreign-items.rs:30:5
- |
-LL | #[inline]
- | ^^^^^^^^^
-LL | static X: u32;
- | -------------- not a function or closure
-
-error[E0518]: attribute should be applied to function or closure
- --> $DIR/inline-trait-and-foreign-items.rs:33:5
- |
-LL | #[inline]
- | ^^^^^^^^^
-LL | type T;
- | ------- not a function or closure
-
warning: `#[inline]` is ignored on constants
--> $DIR/inline-trait-and-foreign-items.rs:7:5
|
LL | type U = impl Trait;
| -------------------- not a function or closure
+error[E0518]: attribute should be applied to function or closure
+ --> $DIR/inline-trait-and-foreign-items.rs:30:5
+ |
+LL | #[inline]
+ | ^^^^^^^^^
+LL | static X: u32;
+ | -------------- not a function or closure
+
+error[E0518]: attribute should be applied to function or closure
+ --> $DIR/inline-trait-and-foreign-items.rs:33:5
+ |
+LL | #[inline]
+ | ^^^^^^^^^
+LL | type T;
+ | ------- not a function or closure
+
error: could not find defining uses
--> $DIR/inline-trait-and-foreign-items.rs:26:14
|
--- /dev/null
+// 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 {};
+}
--- /dev/null
+// (#77273) These characters are in the general categories of
+// "Uppercase/Lowercase Letter".
+// The diagnostics don't provide meaningful suggestions for them
+// as we cannot convert them properly.
+
+// check-pass
+
+#![feature(non_ascii_idents)]
+#![allow(uncommon_codepoints, unused)]
+
+struct 𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝;
+//~^ WARN: type `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name
+
+// FIXME: How we should handle this?
+struct 𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝;
+//~^ WARN: type `𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name
+
+static 𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲: i32 = 1;
+//~^ WARN: static variable `𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲` should have an upper case name
+
+fn main() {
+ let 𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢 = 1;
+ //~^ WARN: variable `𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢` should have a snake case name
+}
--- /dev/null
+warning: type `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name
+ --> $DIR/special-upper-lower-cases.rs:11:8
+ |
+LL | struct 𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝;
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(non_camel_case_types)]` on by default
+
+warning: type `𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name
+ --> $DIR/special-upper-lower-cases.rs:15:8
+ |
+LL | struct 𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝;
+ | ^^^^^^^^^^^ help: convert the identifier to upper camel case: `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝`
+
+warning: static variable `𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲` should have an upper case name
+ --> $DIR/special-upper-lower-cases.rs:18:8
+ |
+LL | static 𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲: i32 = 1;
+ | ^^^^^^^^^^^^
+ |
+ = note: `#[warn(non_upper_case_globals)]` on by default
+
+warning: variable `𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢` should have a snake case name
+ --> $DIR/special-upper-lower-cases.rs:22:9
+ |
+LL | let 𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢 = 1;
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(non_snake_case)]` on by default
+
+warning: 4 warnings emitted
+
-// ignore-cloudabi
// ignore-windows
// ignore-sgx std::os::fortanix_sgx::usercalls::alloc::Iter changes compiler suggestions
// compile-flags: --error-format pretty-json --json=diagnostic-rendered-ansi
"spans": [
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 560,
- "byte_end": 564,
- "line_start": 13,
- "line_end": 13,
+ "byte_start": 541,
+ "byte_end": 545,
+ "line_start": 12,
+ "line_end": 12,
"column_start": 12,
"column_end": 16,
"is_primary": true,
"spans": [
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
},
{
"file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 537,
- "byte_end": 537,
- "line_start": 12,
- "line_end": 12,
+ "byte_start": 518,
+ "byte_end": 518,
+ "line_start": 11,
+ "line_end": 11,
"column_start": 1,
"column_end": 1,
"is_primary": true,
}
],
"rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:13:12\u001b[0m
+\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m let x: Iter;\u001b[0m
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m
error: `#[inline]` is ignored on function prototypes
- --> $DIR/warn-unused-inline-on-fn-prototypes.rs:9:5
+ --> $DIR/warn-unused-inline-on-fn-prototypes.rs:4:5
|
LL | #[inline]
| ^^^^^^^^^
| ^^^^^^^^^^^^^^^^^
error: `#[inline]` is ignored on function prototypes
- --> $DIR/warn-unused-inline-on-fn-prototypes.rs:4:5
+ --> $DIR/warn-unused-inline-on-fn-prototypes.rs:9:5
|
LL | #[inline]
| ^^^^^^^^^
--- /dev/null
+// build-pass
+
+#![no_implicit_prelude]
+
+fn main() {
+ ::std::panic!();
+ ::std::todo!();
+ ::std::unimplemented!();
+ ::std::assert_eq!(0, 0);
+ ::std::assert_ne!(0, 1);
+ ::std::dbg!(123);
+ ::std::unreachable!();
+}
macro_rules! mylambda_tt {
($x:ident, $body:expr) => ({
- fn f($x: isize) -> isize { return $body; };
+ fn f($x: isize) -> isize { return $body; }
f
})
}
//
// (Example: Issue #48042)
#[test]
+#[allow(panic_fmt)]
fn to_format_or_not_to_format() {
// ("{}" is the easiest string to test because if this gets
// sent to format_args!, it'll simply fail to compile.
macro_rules! foo {
($p:path) => ({
- fn f() -> $p { 10 };
+ fn f() -> $p { 10 }
f()
})
}
#[derive(parse())]
//~^ ERROR traits in `#[derive(...)]` don't accept arguments
//~| ERROR cannot find derive macro `parse` in this scope
- //~| ERROR cannot find derive macro `parse` in this scope
path: (),
//~^ ERROR `derive` may only be applied to structs, enums and unions
}
| ^^ help: remove the arguments
error[E0774]: `derive` may only be applied to structs, enums and unions
- --> $DIR/issue-69341-malformed-derive-inert.rs:8:5
+ --> $DIR/issue-69341-malformed-derive-inert.rs:7:5
|
LL | path: (),
| ^^^^^^^^
LL | #[derive(parse())]
| ^^^^^
-error: cannot find derive macro `parse` in this scope
- --> $DIR/issue-69341-malformed-derive-inert.rs:4:14
- |
-LL | #[derive(parse())]
- | ^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0774`.
+++ /dev/null
-#[derive(PartialEq, Eq)]
-pub struct Tag(pub Context, pub u16);
-
-#[derive(PartialEq, Eq)]
-pub enum Context {
- Tiff,
- Exif,
-}
-
-impl Tag {
- const ExifIFDPointer: Tag = Tag(Context::Tiff, 34665);
-}
-
-fn main() {
- match Tag::ExifIFDPointer {
- //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered
- Tag::ExifIFDPointer => {}
- }
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
- --> $DIR/issue-50900.rs:15:11
- |
-LL | pub struct Tag(pub Context, pub u16);
- | ------------------------------------- `Tag` defined here
-...
-LL | match Tag::ExifIFDPointer {
- | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Tag`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
+++ /dev/null
-#[deny(unreachable_patterns)]
-
-fn parse_data1(data: &[u8]) -> u32 {
- match data {
- b"" => 1,
- _ => 2,
- }
-}
-
-fn parse_data2(data: &[u8]) -> u32 {
- match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered
- b"" => 1,
- }
-}
-
-fn parse_data3(data: &[u8; 0]) -> u8 {
- match data {
- b"" => 1,
- }
-}
-
-fn parse_data4(data: &[u8]) -> u8 {
- match data { //~ ERROR non-exhaustive patterns
- b"aaa" => 0,
- [_, _, _] => 1,
- }
-}
-
-fn parse_data5(data: &[u8; 3]) -> u8 {
- match data {
- b"aaa" => 0,
- [_, _, _] => 1,
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
- --> $DIR/type_polymorphic_byte_str_literals.rs:11:11
- |
-LL | match data {
- | ^^^^ pattern `&[_, ..]` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `&[u8]`
-
-error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
- --> $DIR/type_polymorphic_byte_str_literals.rs:23:11
- |
-LL | match data {
- | ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `&[u8]`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
// compile-flags: -Z mir-opt-level=2
-// ignore-cloudabi no std::fs
// build-pass
use std::fs::File;
--- /dev/null
+// Checks that we can build a clone shim for array with generic size.
+// Regression test for issue #79269.
+//
+// build-pass
+// compile-flags: -Zmir-opt-level=2 -Zvalidate-mir
+#![feature(min_const_generics)]
+
+#[derive(Clone)]
+struct Array<T, const N: usize>([T; N]);
+
+fn main() {
+ let _ = Array([0u32, 1u32, 2u32]).clone();
+}
-// Regression test for various issues related to normalization & inlining.
-// * #68347, #77306, #77668 - missed normalization during inlining.
-// * #78442 - missed normalization in validator after inlining.
-//
-// build-pass
+// run-pass
// compile-flags:-Zmir-opt-level=2
+// Previously ICEd because we did not normalize during inlining,
+// see https://github.com/rust-lang/rust/pull/77306 for more discussion.
+
pub fn write() {
create()()
}
-pub fn write_generic<T>(_t: T) {
- hide()();
-}
-
pub fn create() -> impl FnOnce() {
|| ()
}
-pub fn hide() -> impl Fn() {
- write
-}
-
fn main() {
write();
- write_generic(());
}
// run-fail
// error-pattern:drop 1
// error-pattern:drop 2
-// ignore-cloudabi no std::process
// ignore-emscripten no processes
/// Structure which will not allow to be dropped twice.
// run-fail
// error-pattern:drop 1
-// ignore-cloudabi no std::process
// ignore-emscripten no processes
/// Structure which will not allow to be dropped twice.
// error-pattern:drop 3
// error-pattern:drop 2
// error-pattern:drop 1
-// ignore-cloudabi no std::process
// ignore-emscripten no processes
/// Structure which will not allow to be dropped twice.
| doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
| doesn't satisfy `_: FnMut<(&&str,)>`
|
- ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL
+ ::: $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
|
LL | pub struct Filter<I, P> {
| ----------------------- doesn't satisfy `_: Iterator`
-// ignore-cloudabi no std::env support
-
use std::env;
pub struct Foo {
error: missing `struct` for struct definition
- --> $DIR/recovered-block.rs:13:8
+ --> $DIR/recovered-block.rs:11:8
|
LL | pub Foo { text }
| ^
| ^^^^^^
error: expected one of `(` or `<`, found `{`
- --> $DIR/recovered-block.rs:19:9
+ --> $DIR/recovered-block.rs:17:9
|
LL | Foo { text: "".to_string() }
| ^ expected one of `(` or `<`
+++ /dev/null
-enum P {
- C(PC),
-}
-
-enum PC {
- Q,
- QA,
-}
-
-fn test(proto: P) {
- match proto { //~ ERROR non-exhaustive patterns
- P::C(PC::Q) => (),
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `C(QA)` not covered
- --> $DIR/issue-40221.rs:11:11
- |
-LL | / enum P {
-LL | | C(PC),
- | | - not covered
-LL | | }
- | |_- `P` defined here
-...
-LL | match proto {
- | ^^^^^ pattern `C(QA)` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `P`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// check-pass
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
#![feature(never_type)]
-// ignore-cloudabi no std::process
-
fn foo(_: Box<dyn FnMut()>) {}
fn main() {
error[E0277]: cannot add `()` to `usize`
- --> $DIR/issue-13352.rs:9:13
+ --> $DIR/issue-13352.rs:7:13
|
LL | 2_usize + (loop {});
| ^ no implementation for `usize + ()`
// run-pass
// ignore-android
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
#![allow(unused_must_use)]
#![allow(unconditional_recursion)]
// ignore-android: FIXME (#20004)
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
self.x + self.y + z
}
+ //~^^^ ERROR A function with the "rust-call" ABI must take a single non-self argument
}
impl FnOnce<isize> for S {
type Output = isize;
extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
+ //~^ ERROR A function with the "rust-call" ABI must take a single non-self argument
}
fn main() {
+error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+ --> $DIR/overloaded-calls-nontuple.rs:11:5
+ |
+LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple
+ --> $DIR/overloaded-calls-nontuple.rs:19:5
+ |
+LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
- --> $DIR/overloaded-calls-nontuple.rs:26:10
+ --> $DIR/overloaded-calls-nontuple.rs:28:10
|
LL | drop(s(3))
| ^^^^
-error: aborting due to previous error
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0059`.
--- /dev/null
+// build-pass (FIXME(62277): should be check-pass)
+// aux-build:fancy-panic.rs
+
+extern crate fancy_panic;
+
+const C: &str = "abc {}";
+static S: &str = "{bla}";
+
+#[allow(unreachable_code)]
+fn main() {
+ panic!("here's a brace: {"); //~ WARN panic message contains a brace
+ std::panic!("another one: }"); //~ WARN panic message contains a brace
+ core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder
+ assert!(false, "{:03x} {test} bla");
+ //~^ WARN panic message contains unused formatting placeholders
+ debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces
+ panic!(C); // No warning (yet)
+ panic!(S); // No warning (yet)
+ panic!(concat!("{", "}")); //~ WARN panic message contains an unused formatting placeholder
+ panic!(concat!("{", "{")); //~ WARN panic message contains braces
+
+ fancy_panic::fancy_panic!("test {} 123");
+ //~^ WARN panic message contains an unused formatting placeholder
+
+ // Check that the lint only triggers for std::panic and core::panic,
+ // not any panic macro:
+ macro_rules! panic {
+ ($e:expr) => ();
+ }
+ panic!("{}"); // OK
+}
--- /dev/null
+warning: panic message contains a brace
+ --> $DIR/panic-brace.rs:11:29
+ |
+LL | panic!("here's a brace: {");
+ | ^
+ |
+ = note: `#[warn(panic_fmt)]` on by default
+ = note: this message is not used as a format string, but will be in a future Rust edition
+help: add a "{}" format string to use the message literally
+ |
+LL | panic!("{}", "here's a brace: {");
+ | ^^^^^
+
+warning: panic message contains a brace
+ --> $DIR/panic-brace.rs:12:31
+ |
+LL | std::panic!("another one: }");
+ | ^
+ |
+ = note: this message is not used as a format string, but will be in a future Rust edition
+help: add a "{}" format string to use the message literally
+ |
+LL | std::panic!("{}", "another one: }");
+ | ^^^^^
+
+warning: panic message contains an unused formatting placeholder
+ --> $DIR/panic-brace.rs:13:25
+ |
+LL | core::panic!("Hello {}");
+ | ^^
+ |
+ = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition
+help: add the missing argument
+ |
+LL | core::panic!("Hello {}", ...);
+ | ^^^^^
+help: or add a "{}" format string to use the message literally
+ |
+LL | core::panic!("{}", "Hello {}");
+ | ^^^^^
+
+warning: panic message contains unused formatting placeholders
+ --> $DIR/panic-brace.rs:14:21
+ |
+LL | assert!(false, "{:03x} {test} bla");
+ | ^^^^^^ ^^^^^^
+ |
+ = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition
+help: add the missing arguments
+ |
+LL | assert!(false, "{:03x} {test} bla", ...);
+ | ^^^^^
+help: or add a "{}" format string to use the message literally
+ |
+LL | assert!(false, "{}", "{:03x} {test} bla");
+ | ^^^^^
+
+warning: panic message contains braces
+ --> $DIR/panic-brace.rs:16:27
+ |
+LL | debug_assert!(false, "{{}} bla");
+ | ^^^^
+ |
+ = note: this message is not used as a format string, but will be in a future Rust edition
+help: add a "{}" format string to use the message literally
+ |
+LL | debug_assert!(false, "{}", "{{}} bla");
+ | ^^^^^
+
+warning: panic message contains an unused formatting placeholder
+ --> $DIR/panic-brace.rs:19:12
+ |
+LL | panic!(concat!("{", "}"));
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition
+help: add the missing argument
+ |
+LL | panic!(concat!("{", "}"), ...);
+ | ^^^^^
+help: or add a "{}" format string to use the message literally
+ |
+LL | panic!("{}", concat!("{", "}"));
+ | ^^^^^
+
+warning: panic message contains braces
+ --> $DIR/panic-brace.rs:20:5
+ |
+LL | panic!(concat!("{", "{"));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this message is not used as a format string, but will be in a future Rust edition
+help: add a "{}" format string to use the message literally
+ |
+LL | panic!("{}", concat!("{", "{"));
+ | ^^^^^
+
+warning: panic message contains an unused formatting placeholder
+ --> $DIR/panic-brace.rs:22:37
+ |
+LL | fancy_panic::fancy_panic!("test {} 123");
+ | ^^
+ |
+ = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition
+
+warning: 8 warnings emitted
+
// build-fail
// compile-flags:-C panic=abort -C prefer-dynamic
// ignore-musl - no dylibs here
-// ignore-cloudabi
// ignore-emscripten
// ignore-sgx no dynamic lib support
// error-pattern:`panic_unwind` is not compiled with this crate's panic strategy
// compile-flags:-C panic=abort
// aux-build:exit-success-if-unwind.rs
// no-prefer-dynamic
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-macos
#![allow(unused_variables)]
// compile-flags:-C panic=abort
// no-prefer-dynamic
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-macos
#![allow(unused_variables)]
// compile-flags:-C lto -C panic=abort
// no-prefer-dynamic
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// compile-flags:-C lto -C panic=unwind
// no-prefer-dynamic
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
// we never unwind through them.
-// ignore-cloudabi no env and process
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
// ignore-android FIXME #17520
-// ignore-cloudabi spawning processes is not supported
// ignore-openbsd no support for libbacktrace without filename
// ignore-wasm no panic or subprocess support
// ignore-emscripten no panic or subprocess support
-thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:17:5
+thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:16:5
stack backtrace:
0: std::panicking::begin_panic
1: issue_47429_short_backtraces::main
| - item list ends here
error: cannot find macro `default` in this scope
- --> $DIR/default-unmatched-assoc.rs:12:5
+ --> $DIR/default-unmatched-assoc.rs:4:5
|
LL | default!();
| ^^^^^^^
error: cannot find macro `default` in this scope
- --> $DIR/default-unmatched-assoc.rs:4:5
+ --> $DIR/default-unmatched-assoc.rs:12:5
|
LL | default!();
| ^^^^^^^
LL | extern {
| ------ in this `extern` block
LL | async fn fe1();
- | ---------^^^
- | |
- | help: remove the qualifiers: `fn`
+ | ^^^
+ |
+help: remove the qualifiers
+ |
+LL | fn fe1();
+ | ^^
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:52:19
| ------ in this `extern` block
LL | async fn fe1();
LL | unsafe fn fe2();
- | ----------^^^
- | |
- | help: remove the qualifiers: `fn`
+ | ^^^
+ |
+help: remove the qualifiers
+ |
+LL | fn fe2();
+ | ^^
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:53:18
| ------ in this `extern` block
...
LL | const fn fe3();
- | ---------^^^
- | |
- | help: remove the qualifiers: `fn`
+ | ^^^
+ |
+help: remove the qualifiers
+ |
+LL | fn fe3();
+ | ^^
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:54:23
| ------ in this `extern` block
...
LL | extern "C" fn fe4();
- | --------------^^^
- | |
- | help: remove the qualifiers: `fn`
+ | ^^^
+ |
+help: remove the qualifiers
+ |
+LL | fn fe4();
+ | ^^
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:55:42
| ------ in this `extern` block
...
LL | const async unsafe extern "C" fn fe5();
- | ---------------------------------^^^
- | |
- | help: remove the qualifiers: `fn`
+ | ^^^
+ |
+help: remove the qualifiers
+ |
+LL | fn fe5();
+ | ^^
error: functions cannot be both `const` and `async`
--> $DIR/fn-header-semantic-fail.rs:55:9
impl Foo {
pub fn foo(_: i32, self: Box<Self) {}
- //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
+ //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)`
}
fn main() {}
-error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
+error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)`
--> $DIR/issue-62660.rs:7:38
|
LL | pub fn foo(_: i32, self: Box<Self) {}
- | ^ expected one of 7 possible tokens
+ | ^ expected one of 9 possible tokens
error: aborting due to previous error
LL | impl W <s(f;Y(;]
| ^ expected one of 7 possible tokens
-error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
+error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `:`, `<`, `=`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
--> $DIR/issue-63116.rs:3:15
|
LL | impl W <s(f;Y(;]
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot find macro `does_not_exist` in this scope
- --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13
+ --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13
|
-LL | mac1! { does_not_exist!() }
+LL | mac2! { does_not_exist!() }
| ^^^^^^^^^^^^^^
error: cannot find macro `does_not_exist` in this scope
- --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13
+ --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13
|
-LL | mac2! { does_not_exist!() }
+LL | mac1! { does_not_exist!() }
| ^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
}
fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
-//~^ ERROR expected one of `,` or `>`, found `;`
+//~^ ERROR expected one of `,`, `:`, `=`, or `>`, found `;`
fn main() {}
-error: expected one of `,` or `>`, found `;`
+error: expected one of `,`, `:`, `=`, or `>`, found `;`
--> $DIR/lifetime-semicolon.rs:5:30
|
LL | fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
- | ^ expected one of `,` or `>`
+ | ^ expected one of `,`, `:`, `=`, or `>`
error: aborting due to previous error
LL | extern {
| ------ in this `extern` block
LL | const fn foo();
- | ---------^^^
- | |
- | help: remove the qualifiers: `fn`
+ | ^^^
+ |
+help: remove the qualifiers
+ |
+LL | fn foo();
+ | ^^
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/no-const-fn-in-extern-block.rs:4:21
| ------ in this `extern` block
...
LL | const unsafe fn bar();
- | ----------------^^^
- | |
- | help: remove the qualifiers: `fn`
+ | ^^^
+ |
+help: remove the qualifiers
+ |
+LL | fn bar();
+ | ^^
error: aborting due to 2 previous errors
type closure = Box<lt/fn()>;
-//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/`
+//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/`
-error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/`
+error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/`
--> $DIR/removed-syntax-closure-lifetime.rs:1:22
|
LL | type closure = Box<lt/fn()>;
- | ^ expected one of 7 possible tokens
+ | ^ expected one of 9 possible tokens
error: aborting due to previous error
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
#![allow(bare_trait_objects)]
// run-pass
#![allow(deprecated)]
-// ignore-cloudabi no files or I/O
// ignore-wasm32-bare no files or I/O
// ignore-emscripten no files
// ignore-sgx no files
+++ /dev/null
-// check-pass
-
-const FOO: &&&u32 = &&&42;
-
-fn main() {
- match unimplemented!() {
- &&&42 => {},
- FOO => {},
- _ => {},
- }
-}
+++ /dev/null
-#![deny(irrefutable_let_patterns)]
-
-fn main() {
- if let _ = 5 {} //~ ERROR irrefutable if-let pattern
-
- while let _ = 5 { //~ ERROR irrefutable while-let pattern
- break;
- }
-}
+++ /dev/null
-error: irrefutable if-let pattern
- --> $DIR/deny-irrefutable-let-patterns.rs:4:5
- |
-LL | if let _ = 5 {}
- | ^^^^^^^^^^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/deny-irrefutable-let-patterns.rs:1:9
- |
-LL | #![deny(irrefutable_let_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: irrefutable while-let pattern
- --> $DIR/deny-irrefutable-let-patterns.rs:6:5
- |
-LL | / while let _ = 5 {
-LL | | break;
-LL | | }
- | |_____^
-
-error: aborting due to 2 previous errors
-
--- /dev/null
+// run-pass
+
+fn main() {
+ let -2147483648..=2147483647 = 1;
+ let 0..=255 = 0u8;
+ let -128..=127 = 0i8;
+ let '\u{0000}'..='\u{10FFFF}' = 'v';
+}
+++ /dev/null
-// run-pass
-
-#![allow(irrefutable_let_patterns)]
-
-fn main() {
- if let _ = 5 {}
-
- while let _ = 5 {
- break;
- }
-}
+++ /dev/null
-// check-pass
-
-#![allow(unreachable_patterns)]
-
-fn main() {
- const CONST: &[Option<()>; 1] = &[Some(())];
- match &[Some(())] {
- &[None] => {}
- CONST => {}
- &[Some(())] => {}
- }
-}
--- /dev/null
+// check-pass
+
+const FOO: &&&u32 = &&&42;
+
+fn main() {
+ match unimplemented!() {
+ &&&42 => {},
+ FOO => {},
+ _ => {},
+ }
+}
--- /dev/null
+#![deny(irrefutable_let_patterns)]
+
+fn main() {
+ if let _ = 5 {} //~ ERROR irrefutable if-let pattern
+
+ while let _ = 5 { //~ ERROR irrefutable while-let pattern
+ break;
+ }
+}
--- /dev/null
+error: irrefutable if-let pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:4:5
+ |
+LL | if let _ = 5 {}
+ | ^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/deny-irrefutable-let-patterns.rs:1:9
+ |
+LL | #![deny(irrefutable_let_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: irrefutable while-let pattern
+ --> $DIR/deny-irrefutable-let-patterns.rs:6:5
+ |
+LL | / while let _ = 5 {
+LL | | break;
+LL | | }
+ | |_____^
+
+error: aborting due to 2 previous errors
+
+++ /dev/null
-#![feature(precise_pointer_size_matching)]
-#![feature(exclusive_range_pattern)]
-#![deny(unreachable_patterns)]
-#![deny(overlapping_patterns)]
-
-use std::{char, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128};
-
-fn main() {
- let x: u8 = 0;
-
- // A single range covering the entire domain.
- match x {
- 0 ..= 255 => {} // ok
- }
-
- // A combination of ranges and values.
- // These are currently allowed to be overlapping.
- match x {
- 0 ..= 32 => {}
- 33 => {}
- 34 .. 128 => {}
- 100 ..= 200 => {}
- 200 => {} //~ ERROR unreachable pattern
- 201 ..= 255 => {}
- }
-
- // An incomplete set of values.
- match x { //~ ERROR non-exhaustive patterns
- 0 .. 128 => {}
- }
-
- // A more incomplete set of values.
- match x { //~ ERROR non-exhaustive patterns
- 0 ..= 10 => {}
- 20 ..= 30 => {}
- 35 => {}
- 70 .. 255 => {}
- }
-
- let x: i8 = 0;
- match x { //~ ERROR non-exhaustive patterns
- -7 => {}
- -5..=120 => {}
- -2..=20 => {}
- //~^ ERROR unreachable pattern
- 125 => {}
- }
-
- // Let's test other types too!
- let c: char = '\u{0}';
- match c {
- '\u{0}' ..= char::MAX => {} // ok
- }
-
- // We can actually get away with just covering the
- // following two ranges, which correspond to all
- // valid Unicode Scalar Values.
- match c {
- '\u{0000}' ..= '\u{D7FF}' => {}
- '\u{E000}' ..= '\u{10_FFFF}' => {}
- }
-
- match 0u16 {
- 0 ..= u16::MAX => {} // ok
- }
-
- match 0u32 {
- 0 ..= u32::MAX => {} // ok
- }
-
- match 0u64 {
- 0 ..= u64::MAX => {} // ok
- }
-
- match 0u128 {
- 0 ..= u128::MAX => {} // ok
- }
-
- match 0i8 {
- -128 ..= 127 => {} // ok
- }
-
- match 0i8 { //~ ERROR non-exhaustive patterns
- -127 ..= 127 => {}
- }
-
- match 0i16 {
- i16::MIN ..= i16::MAX => {} // ok
- }
-
- match 0i16 { //~ ERROR non-exhaustive patterns
- i16::MIN ..= -1 => {}
- 1 ..= i16::MAX => {}
- }
-
- match 0i32 {
- i32::MIN ..= i32::MAX => {} // ok
- }
-
- match 0i64 {
- i64::MIN ..= i64::MAX => {} // ok
- }
-
- match 0i128 {
- i128::MIN ..= i128::MAX => {} // ok
- }
-
- // Make sure that guards don't factor into the exhaustiveness checks.
- match 0u8 { //~ ERROR non-exhaustive patterns
- 0 .. 128 => {}
- 128 ..= 255 if true => {}
- }
-
- match 0u8 {
- 0 .. 128 => {}
- 128 ..= 255 if false => {}
- 128 ..= 255 => {} // ok, because previous arm was guarded
- }
-
- // Now things start getting a bit more interesting. Testing products!
- match (0u8, Some(())) { //~ ERROR non-exhaustive patterns
- (1, _) => {}
- (_, None) => {}
- }
-
- match (0u8, true) { //~ ERROR non-exhaustive patterns
- (0 ..= 125, false) => {}
- (128 ..= 255, false) => {}
- (0 ..= 255, true) => {}
- }
-
- match (0u8, true) { // ok
- (0 ..= 125, false) => {}
- (128 ..= 255, false) => {}
- (0 ..= 255, true) => {}
- (125 .. 128, false) => {}
- }
-
- match 0u8 {
- 0 .. 2 => {}
- 1 ..= 2 => {} //~ ERROR multiple patterns covering the same range
- _ => {}
- }
-
- const LIM: u128 = u128::MAX - 1;
- match 0u128 { //~ ERROR non-exhaustive patterns
- 0 ..= LIM => {}
- }
-
- match 0u128 { //~ ERROR non-exhaustive patterns
- 0 ..= 4 => {}
- }
-
- match 0u128 { //~ ERROR non-exhaustive patterns
- 4 ..= u128::MAX => {}
- }
-
- const FOO: i32 = 42;
- const BAR: &i32 = &42;
- match &0 {
- &42 => {}
- &FOO => {} //~ ERROR unreachable pattern
- BAR => {} //~ ERROR unreachable pattern
- _ => {}
- }
-
- // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933
- match &0 {
- BAR => {} // ok
- _ => {}
- }
-}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/exhaustive_integer_patterns.rs:23:9
- |
-LL | 200 => {}
- | ^^^
- |
-note: the lint level is defined here
- --> $DIR/exhaustive_integer_patterns.rs:3:9
- |
-LL | #![deny(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
- --> $DIR/exhaustive_integer_patterns.rs:28:11
- |
-LL | match x {
- | ^ pattern `128_u8..=u8::MAX` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `u8`
-
-error[E0004]: non-exhaustive patterns: `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered
- --> $DIR/exhaustive_integer_patterns.rs:33:11
- |
-LL | match x {
- | ^ patterns `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `u8`
-
-error: unreachable pattern
- --> $DIR/exhaustive_integer_patterns.rs:44:9
- |
-LL | -2..=20 => {}
- | ^^^^^^^
-
-error[E0004]: non-exhaustive patterns: `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered
- --> $DIR/exhaustive_integer_patterns.rs:41:11
- |
-LL | match x {
- | ^ patterns `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `i8`
-
-error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
- --> $DIR/exhaustive_integer_patterns.rs:83:11
- |
-LL | match 0i8 {
- | ^^^ pattern `i8::MIN` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `i8`
-
-error[E0004]: non-exhaustive patterns: `0_i16` not covered
- --> $DIR/exhaustive_integer_patterns.rs:91:11
- |
-LL | match 0i16 {
- | ^^^^ pattern `0_i16` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `i16`
-
-error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
- --> $DIR/exhaustive_integer_patterns.rs:109:11
- |
-LL | match 0u8 {
- | ^^^ pattern `128_u8..=u8::MAX` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `u8`
-
-error[E0004]: non-exhaustive patterns: `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered
- --> $DIR/exhaustive_integer_patterns.rs:121:11
- |
-LL | match (0u8, Some(())) {
- | ^^^^^^^^^^^^^^^ patterns `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `(u8, Option<()>)`
-
-error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
- --> $DIR/exhaustive_integer_patterns.rs:126:11
- |
-LL | match (0u8, true) {
- | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `(u8, bool)`
-
-error: multiple patterns covering the same range
- --> $DIR/exhaustive_integer_patterns.rs:141:9
- |
-LL | 0 .. 2 => {}
- | ------ this range overlaps on `1_u8`
-LL | 1 ..= 2 => {}
- | ^^^^^^^ overlapping patterns
- |
-note: the lint level is defined here
- --> $DIR/exhaustive_integer_patterns.rs:4:9
- |
-LL | #![deny(overlapping_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
- --> $DIR/exhaustive_integer_patterns.rs:146:11
- |
-LL | match 0u128 {
- | ^^^^^ pattern `u128::MAX` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `u128`
-
-error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
- --> $DIR/exhaustive_integer_patterns.rs:150:11
- |
-LL | match 0u128 {
- | ^^^^^ pattern `5_u128..=u128::MAX` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `u128`
-
-error[E0004]: non-exhaustive patterns: `0_u128..=3_u128` not covered
- --> $DIR/exhaustive_integer_patterns.rs:154:11
- |
-LL | match 0u128 {
- | ^^^^^ pattern `0_u128..=3_u128` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `u128`
-
-error: unreachable pattern
- --> $DIR/exhaustive_integer_patterns.rs:162:9
- |
-LL | &FOO => {}
- | ^^^^
-
-error: unreachable pattern
- --> $DIR/exhaustive_integer_patterns.rs:163:9
- |
-LL | BAR => {}
- | ^^^
-
-error: aborting due to 16 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![allow(illegal_floating_point_literal_pattern)]
+#![deny(unreachable_patterns)]
+
+fn main() {
+ match 0.0 {
+ 0.0..=1.0 => {}
+ _ => {} // ok
+ }
+
+ match 0.0 { //~ ERROR non-exhaustive patterns
+ 0.0..=1.0 => {}
+ }
+
+ match 1.0f64 {
+ 0.01f64 ..= 6.5f64 => {}
+ 0.02f64 => {} //~ ERROR unreachable pattern
+ _ => {}
+ };
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/floats.rs:10:11
+ |
+LL | match 0.0 {
+ | ^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `f64`
+
+error: unreachable pattern
+ --> $DIR/floats.rs:16:7
+ |
+LL | 0.02f64 => {}
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/floats.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
+++ /dev/null
-// run-pass
-
-#![allow(non_snake_case)]
-
-#[derive(Copy, Clone)]
-enum Q { R(Option<usize>) }
-
-fn xyzzy(q: Q) -> usize {
- match q {
- Q::R(S) if S.is_some() => { 0 }
- _ => 1
- }
-}
-
-
-pub fn main() {
- assert_eq!(xyzzy(Q::R(Some(5))), 0);
-}
--- /dev/null
+#![feature(exclusive_range_pattern)]
+#![deny(unreachable_patterns)]
+
+enum Q { R(Option<usize>) }
+
+pub fn main() {
+ match Q::R(None) {
+ Q::R(S) if S.is_some() => {}
+ _ => {}
+ }
+
+ match 0u8 { //~ ERROR non-exhaustive patterns
+ 0 .. 128 => {}
+ 128 ..= 255 if true => {}
+ }
+
+ match 0u8 {
+ 0 .. 128 => {}
+ 128 ..= 255 if false => {}
+ 128 ..= 255 => {} // ok, because previous arm was guarded
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
+ --> $DIR/guards.rs:12:11
+ |
+LL | match 0u8 {
+ | ^^^ pattern `128_u8..=u8::MAX` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![feature(exclusive_range_pattern)]
+#![feature(assoc_char_consts)]
+#![deny(unreachable_patterns)]
+
+macro_rules! m {
+ ($s:expr, $($t:tt)+) => {
+ match $s { $($t)+ => {} }
+ }
+}
+
+macro_rules! test_int {
+ ($s:expr, $min:path, $max:path) => {
+ m!($s, $min..=$max);
+ m!($s, $min..5 | 5..=$max);
+ m!($s, $min..=4 | 5..=$max);
+ m!($s, $min..$max | $max);
+ m!(($s, true), ($min..5, true) | (5..=$max, true) | ($min..=$max, false));
+ }
+}
+
+fn main() {
+ test_int!(0u8, u8::MIN, u8::MAX);
+ test_int!(0u16, u16::MIN, u16::MAX);
+ test_int!(0u32, u32::MIN, u32::MAX);
+ test_int!(0u64, u64::MIN, u64::MAX);
+ test_int!(0u128, u128::MIN, u128::MAX);
+
+ test_int!(0i8, i8::MIN, i8::MAX);
+ test_int!(0i16, i16::MIN, i16::MAX);
+ test_int!(0i32, i32::MIN, i32::MAX);
+ test_int!(0i64, i64::MIN, i64::MAX);
+ test_int!(0i128, i128::MIN, i128::MAX);
+
+ m!('a', '\u{0}'..=char::MAX);
+ m!('a', '\u{0}'..='\u{10_FFFF}');
+ // We can get away with just covering the following two ranges, which correspond to all valid
+ // Unicode Scalar Values.
+ m!('a', '\u{0}'..='\u{D7FF}' | '\u{E000}'..=char::MAX);
+ m!('a', '\u{0}'..'\u{D7FF}' | '\u{D7FF}' | '\u{E000}'..=char::MAX);
+
+ let 0..=255 = 0u8;
+ let -128..=127 = 0i8;
+ let -2147483648..=2147483647 = 0i32;
+ let '\u{0000}'..='\u{10FFFF}' = 'v';
+
+ // Almost exhaustive
+ m!(0u8, 0..255); //~ ERROR non-exhaustive patterns
+ m!(0u8, 0..=254); //~ ERROR non-exhaustive patterns
+ m!(0u8, 1..=255); //~ ERROR non-exhaustive patterns
+ m!(0u8, 0..42 | 43..=255); //~ ERROR non-exhaustive patterns
+ m!(0i8, -128..127); //~ ERROR non-exhaustive patterns
+ m!(0i8, -128..=126); //~ ERROR non-exhaustive patterns
+ m!(0i8, -127..=127); //~ ERROR non-exhaustive patterns
+ match 0i8 { //~ ERROR non-exhaustive patterns
+ i8::MIN ..= -1 => {}
+ 1 ..= i8::MAX => {}
+ }
+ const ALMOST_MAX: u128 = u128::MAX - 1;
+ m!(0u128, 0..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+ m!(0u128, 0..=4); //~ ERROR non-exhaustive patterns
+ m!(0u128, 1..=u128::MAX); //~ ERROR non-exhaustive patterns
+
+ // More complicatedly (non-)exhaustive
+ match 0u8 {
+ 0 ..= 30 => {}
+ 20 ..= 70 => {}
+ 50 ..= 255 => {}
+ }
+ match (0u8, true) { //~ ERROR non-exhaustive patterns
+ (0 ..= 125, false) => {}
+ (128 ..= 255, false) => {}
+ (0 ..= 255, true) => {}
+ }
+ match (0u8, true) { // ok
+ (0 ..= 125, false) => {}
+ (128 ..= 255, false) => {}
+ (0 ..= 255, true) => {}
+ (125 .. 128, false) => {}
+ }
+ match (true, 0u8) {
+ (true, 0 ..= 255) => {}
+ (false, 0 ..= 125) => {}
+ (false, 128 ..= 255) => {}
+ (false, 125 .. 128) => {}
+ }
+ match Some(0u8) {
+ None => {}
+ Some(0 ..= 125) => {}
+ Some(128 ..= 255) => {}
+ Some(125 .. 128) => {}
+ }
+ const FOO: u8 = 41;
+ const BAR: &u8 = &42;
+ match &0u8 {
+ 0..41 => {}
+ &FOO => {}
+ BAR => {}
+ 43..=255 => {}
+ }
+
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:47:8
+ |
+LL | m!(0u8, 0..255);
+ | ^^^ pattern `u8::MAX` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:48:8
+ |
+LL | m!(0u8, 0..=254);
+ | ^^^ pattern `u8::MAX` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: `0_u8` not covered
+ --> $DIR/exhaustiveness.rs:49:8
+ |
+LL | m!(0u8, 1..=255);
+ | ^^^ pattern `0_u8` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: `42_u8` not covered
+ --> $DIR/exhaustiveness.rs:50:8
+ |
+LL | m!(0u8, 0..42 | 43..=255);
+ | ^^^ pattern `42_u8` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:51:8
+ |
+LL | m!(0i8, -128..127);
+ | ^^^ pattern `i8::MAX` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `i8`
+
+error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
+ --> $DIR/exhaustiveness.rs:52:8
+ |
+LL | m!(0i8, -128..=126);
+ | ^^^ pattern `i8::MAX` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `i8`
+
+error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
+ --> $DIR/exhaustiveness.rs:53:8
+ |
+LL | m!(0i8, -127..=127);
+ | ^^^ pattern `i8::MIN` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `i8`
+
+error[E0004]: non-exhaustive patterns: `0_i8` not covered
+ --> $DIR/exhaustiveness.rs:54:11
+ |
+LL | match 0i8 {
+ | ^^^ pattern `0_i8` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `i8`
+
+error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
+ --> $DIR/exhaustiveness.rs:59:8
+ |
+LL | m!(0u128, 0..=ALMOST_MAX);
+ | ^^^^^ pattern `u128::MAX` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `u128`
+
+error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
+ --> $DIR/exhaustiveness.rs:60:8
+ |
+LL | m!(0u128, 0..=4);
+ | ^^^^^ pattern `5_u128..=u128::MAX` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `u128`
+
+error[E0004]: non-exhaustive patterns: `0_u128` not covered
+ --> $DIR/exhaustiveness.rs:61:8
+ |
+LL | m!(0u128, 1..=u128::MAX);
+ | ^^^^^ pattern `0_u128` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = 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
+ |
+LL | match (0u8, true) {
+ | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `(u8, bool)`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![feature(exclusive_range_pattern)]
+#![deny(overlapping_patterns)]
+
+macro_rules! m {
+ ($s:expr, $t1:pat, $t2:pat) => {
+ match $s {
+ $t1 => {}
+ $t2 => {}
+ _ => {}
+ }
+ }
+}
+
+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, 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, 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, 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, 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, 25, 20..=30);
+ m!(0u8, 30, 20..=30); //~ ERROR multiple patterns covering the same range
+
+ match (0u8, true) {
+ (0..=10, true) => {}
+ (10..20, true) => {} // not detected
+ (10..20, false) => {}
+ _ => {}
+ }
+ match (true, 0u8) {
+ (true, 0..=10) => {}
+ (true, 10..20) => {} //~ ERROR multiple patterns covering the same range
+ (false, 10..20) => {}
+ _ => {}
+ }
+ match Some(0u8) {
+ Some(0..=10) => {}
+ Some(10..20) => {} //~ ERROR multiple patterns covering the same range
+ _ => {}
+ }
+}
--- /dev/null
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:15:22
+ |
+LL | m!(0u8, 20..=30, 30..=40);
+ | ------- ^^^^^^^ overlapping patterns
+ | |
+ | this range overlaps on `30_u8`
+ |
+note: the lint level is defined here
+ --> $DIR/overlapping_range_endpoints.rs:2:9
+ |
+LL | #![deny(overlapping_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:16:22
+ |
+LL | m!(0u8, 30..=40, 20..=30);
+ | ------- ^^^^^^^ overlapping patterns
+ | |
+ | this range overlaps on `30_u8`
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:19:22
+ |
+LL | m!(0u8, 20.. 30, 29..=40);
+ | ------- ^^^^^^^ overlapping patterns
+ | |
+ | this range overlaps on `29_u8`
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:23:22
+ |
+LL | m!(0u8, 20..=30, 30..=31);
+ | ------- ^^^^^^^ overlapping patterns
+ | |
+ | this range overlaps on `30_u8`
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:27:22
+ |
+LL | m!(0u8, 20..=30, 19..=20);
+ | ------- ^^^^^^^ overlapping patterns
+ | |
+ | this range overlaps on `20_u8`
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:32:17
+ |
+LL | m!(0u8, 20, 20..=30);
+ | -- ^^^^^^^ overlapping patterns
+ | |
+ | this range overlaps on `20_u8`
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:34:17
+ |
+LL | m!(0u8, 30, 20..=30);
+ | -- ^^^^^^^ overlapping patterns
+ | |
+ | this range overlaps on `30_u8`
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:44:16
+ |
+LL | (true, 0..=10) => {}
+ | ------ this range overlaps on `10_u8`
+LL | (true, 10..20) => {}
+ | ^^^^^^ overlapping patterns
+
+error: multiple patterns covering the same range
+ --> $DIR/overlapping_range_endpoints.rs:50:14
+ |
+LL | Some(0..=10) => {}
+ | ------ this range overlaps on `10_u8`
+LL | Some(10..20) => {}
+ | ^^^^^^ overlapping patterns
+
+error: aborting due to 9 previous errors
+
--- /dev/null
+#![feature(precise_pointer_size_matching)]
+#![feature(exclusive_range_pattern)]
+
+macro_rules! m {
+ ($s:expr, $($t:tt)+) => {
+ match $s { $($t)+ => {} }
+ }
+}
+
+fn main() {
+ match 0usize {
+ 0 ..= usize::MAX => {}
+ }
+
+ match 0isize {
+ isize::MIN ..= isize::MAX => {}
+ }
+
+ m!(0usize, 0..=usize::MAX);
+ m!(0usize, 0..5 | 5..=usize::MAX);
+ m!(0usize, 0..usize::MAX | usize::MAX);
+ m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
+
+ m!(0isize, isize::MIN..=isize::MAX);
+ m!(0isize, isize::MIN..5 | 5..=isize::MAX);
+ m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+ m!((0isize, true), (isize::MIN..5, true)
+ | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
+
+ match 0isize {
+ isize::MIN ..= -1 => {}
+ 0 => {}
+ 1 ..= isize::MAX => {}
+ }
+
+ match 7usize {}
+ //~^ ERROR non-exhaustive patterns
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: type `usize` is non-empty
+ --> $DIR/pointer-sized-int-allow.rs:36:11
+ |
+LL | match 7usize {}
+ | ^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![feature(exclusive_range_pattern)]
+
+macro_rules! m {
+ ($s:expr, $($t:tt)+) => {
+ match $s { $($t)+ => {} }
+ }
+}
+
+fn main() {
+ match 0usize {
+ //~^ ERROR non-exhaustive patterns
+ 0 ..= usize::MAX => {}
+ }
+
+ match 0isize {
+ //~^ ERROR non-exhaustive patterns
+ isize::MIN ..= isize::MAX => {}
+ }
+
+ m!(0usize, 0..=usize::MAX);
+ //~^ ERROR non-exhaustive patterns
+ m!(0usize, 0..5 | 5..=usize::MAX);
+ //~^ ERROR non-exhaustive patterns
+ m!(0usize, 0..usize::MAX | usize::MAX);
+ //~^ ERROR non-exhaustive patterns
+ m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
+ //~^ ERROR non-exhaustive patterns
+
+ m!(0isize, isize::MIN..=isize::MAX);
+ //~^ ERROR non-exhaustive patterns
+ m!(0isize, isize::MIN..5 | 5..=isize::MAX);
+ //~^ ERROR non-exhaustive patterns
+ m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+ //~^ ERROR non-exhaustive patterns
+ m!((0isize, true), (isize::MIN..5, true)
+ | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
+ //~^^ ERROR non-exhaustive patterns
+
+ match 0isize {
+ //~^ ERROR non-exhaustive patterns
+ isize::MIN ..= -1 => {}
+ 0 => {}
+ 1 ..= isize::MAX => {}
+ }
+
+ match 7usize {}
+ //~^ ERROR non-exhaustive patterns
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:10:11
+ |
+LL | match 0usize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:15:11
+ |
+LL | match 0isize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:20:8
+ |
+LL | m!(0usize, 0..=usize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:22:8
+ |
+LL | m!(0usize, 0..5 | 5..=usize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:24:8
+ |
+LL | m!(0usize, 0..usize::MAX | usize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+ --> $DIR/pointer-sized-int-deny.rs:26:8
+ |
+LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
+ | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `(usize, bool)`
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:29:8
+ |
+LL | m!(0isize, isize::MIN..=isize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:31:8
+ |
+LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:33:8
+ |
+LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+ --> $DIR/pointer-sized-int-deny.rs:35:8
+ |
+LL | m!((0isize, true), (isize::MIN..5, true)
+ | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `(isize, bool)`
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/pointer-sized-int-deny.rs:39:11
+ |
+LL | match 0isize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: type `usize` is non-empty
+ --> $DIR/pointer-sized-int-deny.rs:46:11
+ |
+LL | match 7usize {}
+ | ^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+// This tests that the lint message explains the reason for the error.
+fn main() {
+ match 0usize {
+ //~^ ERROR non-exhaustive patterns: `_` not covered
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `usize`
+ //~| NOTE `usize` does not have a fixed maximum value
+ 0..=usize::MAX => {}
+ }
+
+ match 0isize {
+ //~^ ERROR non-exhaustive patterns: `_` not covered
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `isize`
+ //~| NOTE `isize` does not have a fixed maximum value
+ isize::MIN..=isize::MAX => {}
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/precise_pointer_matching-message.rs:3:11
+ |
+LL | match 0usize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/precise_pointer_matching-message.rs:11:11
+ |
+LL | match 0isize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![feature(exclusive_range_pattern)]
+#![deny(unreachable_patterns)]
+
+macro_rules! m {
+ ($s:expr, $t1:pat, $t2:pat) => {
+ match $s {
+ $t1 => {}
+ $t2 => {}
+ _ => {}
+ }
+ }
+}
+
+fn main() {
+ m!(0u8, 42, 41);
+ m!(0u8, 42, 42); //~ ERROR unreachable pattern
+ m!(0u8, 42, 43);
+
+ m!(0u8, 20..=30, 19);
+ m!(0u8, 20..=30, 20); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 21); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 25); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 29); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 31);
+ m!(0u8, 20..30, 19);
+ m!(0u8, 20..30, 20); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 21); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 25); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 29); //~ ERROR unreachable pattern
+ m!(0u8, 20..30, 30);
+ m!(0u8, 20..30, 31);
+
+ m!(0u8, 20..=30, 20..=30); //~ ERROR unreachable pattern
+ m!(0u8, 20.. 30, 20.. 30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 20.. 30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 19..=30);
+ m!(0u8, 20..=30, 21..=30); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 20..=29); //~ ERROR unreachable pattern
+ m!(0u8, 20..=30, 20..=31);
+ m!('a', 'A'..='z', 'a'..='z'); //~ ERROR unreachable pattern
+
+ match 0u8 {
+ 5 => {},
+ 6 => {},
+ 7 => {},
+ 8 => {},
+ 5..=8 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0u8 {
+ 0..10 => {},
+ 10..20 => {},
+ 5..15 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0u8 {
+ 0..10 => {},
+ 10..20 => {},
+ 20..30 => {},
+ 5..25 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0u8 {
+ 0..10 => {},
+ 10 => {},
+ 11..=23 => {},
+ 19..30 => {},
+ 5..25 => {}, //~ ERROR unreachable pattern
+ _ => {},
+ }
+ match 0usize {
+ 0..10 => {},
+ 10..20 => {},
+ 5..15 => {}, // FIXME: should be unreachable
+ _ => {},
+ }
+ // Chars between '\u{D7FF}' and '\u{E000}' are invalid even though ranges that contain them are
+ // allowed.
+ match 'a' {
+ _ => {},
+ '\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern
+ }
+ match 'a' {
+ '\u{0}'..='\u{D7FF}' => {},
+ '\u{E000}'..='\u{10_FFFF}' => {},
+ '\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable
+ }
+
+ match (0u8, true) {
+ (0..=255, false) => {}
+ (0..=255, true) => {} // ok
+ }
+ match (true, 0u8) {
+ (false, 0..=255) => {}
+ (true, 0..=255) => {} // ok
+ }
+
+ const FOO: i32 = 42;
+ const BAR: &i32 = &42;
+ match &0 {
+ &42 => {}
+ &FOO => {} //~ ERROR unreachable pattern
+ BAR => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+ // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933
+ match &0 {
+ BAR => {} // ok
+ _ => {}
+ }
+}
--- /dev/null
+error: unreachable pattern
+ --> $DIR/reachability.rs:16:17
+ |
+LL | m!(0u8, 42, 42);
+ | ^^
+ |
+note: the lint level is defined here
+ --> $DIR/reachability.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:20:22
+ |
+LL | m!(0u8, 20..=30, 20);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:21:22
+ |
+LL | m!(0u8, 20..=30, 21);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:22:22
+ |
+LL | m!(0u8, 20..=30, 25);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:23:22
+ |
+LL | m!(0u8, 20..=30, 29);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:24:22
+ |
+LL | m!(0u8, 20..=30, 30);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:27:21
+ |
+LL | m!(0u8, 20..30, 20);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:28:21
+ |
+LL | m!(0u8, 20..30, 21);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:29:21
+ |
+LL | m!(0u8, 20..30, 25);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:30:21
+ |
+LL | m!(0u8, 20..30, 29);
+ | ^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:34:22
+ |
+LL | m!(0u8, 20..=30, 20..=30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:35:22
+ |
+LL | m!(0u8, 20.. 30, 20.. 30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:36:22
+ |
+LL | m!(0u8, 20..=30, 20.. 30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:38:22
+ |
+LL | m!(0u8, 20..=30, 21..=30);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:39:22
+ |
+LL | m!(0u8, 20..=30, 20..=29);
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:41:24
+ |
+LL | m!('a', 'A'..='z', 'a'..='z');
+ | ^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:48:9
+ |
+LL | 5..=8 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:54:9
+ |
+LL | 5..15 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:61:9
+ |
+LL | 5..25 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:69:9
+ |
+LL | 5..25 => {},
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:82:9
+ |
+LL | '\u{D7FF}'..='\u{E000}' => {},
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:103:9
+ |
+LL | &FOO => {}
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/reachability.rs:104:9
+ |
+LL | BAR => {}
+ | ^^^
+
+error: aborting due to 23 previous errors
+
+++ /dev/null
-// run-pass
-
-fn main() {
- let -2147483648..=2147483647 = 1;
- let 0..=255 = 0u8;
- let -128..=127 = 0i8;
- let '\u{0000}'..='\u{10FFFF}' = 'v';
-}
--- /dev/null
+// run-pass
+
+#![allow(irrefutable_let_patterns)]
+
+fn main() {
+ if let _ = 5 {}
+
+ while let _ = 5 {
+ break;
+ }
+}
--- /dev/null
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![deny(unreachable_patterns)]
+
+enum IntList {
+ Cons(isize, Box<IntList>),
+ Nil
+}
+
+fn tail(source_list: &IntList) -> IntList {
+ match source_list {
+ &IntList::Cons(val, box ref next_list) => tail(next_list),
+ &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil),
+//~^ ERROR unreachable pattern
+ _ => panic!()
+ }
+}
+
+fn main() {}
--- /dev/null
+error: unreachable pattern
+ --> $DIR/issue-12116.rs:15:9
+ |
+LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-12116.rs:5:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![deny(unreachable_patterns)]
+
+fn main() {
+ let sl = vec![1,2,3];
+ let v: isize = match &*sl {
+ &[] => 0,
+ &[a,b,c] => 3,
+ &[a, ref rest @ ..] => a,
+ &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern
+ };
+}
--- /dev/null
+error: unreachable pattern
+ --> $DIR/issue-12369.rs:9:9
+ |
+LL | &[10,a, ref rest @ ..] => 10
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-12369.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![allow(overflowing_literals)]
+#![deny(unreachable_patterns)]
+
+fn test(val: u8) {
+ match val {
+ 256 => print!("0b1110\n"),
+ 512 => print!("0b1111\n"),
+ //~^ ERROR: unreachable pattern
+ _ => print!("fail\n"),
+ }
+}
+
+fn main() {
+ test(1);
+}
--- /dev/null
+error: unreachable pattern
+ --> $DIR/issue-13727.rs:7:5
+ |
+LL | 512 => print!("0b1111\n"),
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-13727.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+pub enum T {
+ T1(()),
+ T2(())
+}
+
+pub enum V {
+ V1(isize),
+ V2(bool)
+}
+
+fn main() {
+ match (T::T1(()), V::V2(true)) {
+ //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered
+ (T::T1(()), V::V1(i)) => (),
+ (T::T2(()), V::V2(b)) => ()
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered
+ --> $DIR/issue-15129.rs:12:11
+ |
+LL | match (T::T1(()), V::V2(true)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `(T, V)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+fn foo(a: Option<usize>, b: Option<usize>) {
+ match (a,b) {
+ //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
+ (Some(a), Some(b)) if a == b => { }
+ (Some(_), None) |
+ (None, Some(_)) => { }
+ }
+}
+
+fn main() {
+ foo(None, None);
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `(None, None)` not covered
+ --> $DIR/issue-2111.rs:2:9
+ |
+LL | match (a,b) {
+ | ^^^^^ pattern `(None, None)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `(Option<usize>, Option<usize>)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![deny(unreachable_patterns)]
+
+fn main() {
+ match "world" {
+ "hello" => {}
+ _ => {},
+ }
+
+ match "world" {
+ ref _x if false => {}
+ "hello" => {}
+ "hello" => {} //~ ERROR unreachable pattern
+ _ => {},
+ }
+}
--- /dev/null
+error: unreachable pattern
+ --> $DIR/issue-30240-b.rs:12:9
+ |
+LL | "hello" => {}
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-30240-b.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+fn main() {
+ let &ref a = &[0i32] as &[_];
+ assert_eq!(a, &[0i32] as &[_]);
+
+ let &ref a = "hello";
+ assert_eq!(a, "hello");
+
+ match "foo" {
+ "fool" => unreachable!(),
+ "foo" => {},
+ ref _x => unreachable!()
+ }
+}
--- /dev/null
+fn main() {
+ match "world" { //~ ERROR non-exhaustive patterns: `&_`
+ "hello" => {}
+ }
+
+ match "world" { //~ ERROR non-exhaustive patterns: `&_`
+ ref _x if false => {}
+ "hello" => {}
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `&_` not covered
+ --> $DIR/issue-30240.rs:2:11
+ |
+LL | match "world" {
+ | ^^^^^^^ pattern `&_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `&str`
+
+error[E0004]: non-exhaustive patterns: `&_` not covered
+ --> $DIR/issue-30240.rs:6:11
+ |
+LL | match "world" {
+ | ^^^^^^^ pattern `&_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `&str`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+fn main() {
+ match () { } //~ ERROR non-exhaustive
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: type `()` is non-empty
+ --> $DIR/issue-3096-1.rs:2:11
+ |
+LL | match () { }
+ | ^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+enum Bottom { }
+
+fn main() {
+ let x = &() as *const () as *const Bottom;
+ match x { } //~ ERROR non-exhaustive patterns
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty
+ --> $DIR/issue-3096-2.rs:5:11
+ |
+LL | match x { }
+ | ^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `*const Bottom`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(non_snake_case)]
+#![deny(unreachable_patterns)]
+
+#[derive(Clone, Copy)]
+enum Enum {
+ Var1,
+ Var2,
+}
+
+fn main() {
+ use Enum::*;
+ let s = Var1;
+ match s {
+ Var1 => (),
+ Var3 => (),
+ Var2 => (),
+ //~^ ERROR unreachable pattern
+ };
+ match &s {
+ &Var1 => (),
+ &Var3 => (),
+ &Var2 => (),
+ //~^ ERROR unreachable pattern
+ };
+ let t = (Var1, Var1);
+ match t {
+ (Var1, b) => (),
+ (c, d) => (),
+ anything => ()
+ //~^ ERROR unreachable pattern
+ };
+}
--- /dev/null
+error: unreachable pattern
+ --> $DIR/issue-31221.rs:18:9
+ |
+LL | Var3 => (),
+ | ---- matches any value
+LL | Var2 => (),
+ | ^^^^ unreachable pattern
+ |
+note: the lint level is defined here
+ --> $DIR/issue-31221.rs:4:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/issue-31221.rs:24:9
+ |
+LL | &Var3 => (),
+ | ----- matches any value
+LL | &Var2 => (),
+ | ^^^^^ unreachable pattern
+
+error: unreachable pattern
+ --> $DIR/issue-31221.rs:31:9
+ |
+LL | (c, d) => (),
+ | ------ matches any value
+LL | anything => ()
+ | ^^^^^^^^ unreachable pattern
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+enum Thing {
+ Foo(u8),
+ Bar,
+ Baz
+}
+
+fn main() {
+ let Thing::Foo(y) = Thing::Foo(1);
+ //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered
+}
--- /dev/null
+error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
+ --> $DIR/issue-31561.rs:8:9
+ |
+LL | / enum Thing {
+LL | | Foo(u8),
+LL | | Bar,
+ | | --- not covered
+LL | | Baz
+ | | --- not covered
+LL | | }
+ | |_- `Thing` defined here
+...
+LL | let Thing::Foo(y) = Thing::Foo(1);
+ | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ = note: the matched value is of type `Thing`
+help: you might want to use `if let` to ignore the variant that isn't matched
+ |
+LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ }
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0005`.
--- /dev/null
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+
+struct HTMLImageData {
+ image: Option<String>
+}
+
+struct ElementData {
+ kind: Box<ElementKind>
+}
+
+enum ElementKind {
+ HTMLImageElement(HTMLImageData)
+}
+
+enum NodeKind {
+ Element(ElementData)
+}
+
+struct NodeData {
+ kind: Box<NodeKind>,
+}
+
+fn main() {
+ let mut id = HTMLImageData { image: None };
+ let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) };
+ let n = NodeData {kind : box NodeKind::Element(ed)};
+ // n.b. span could be better
+ match n.kind {
+ box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
+ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+ },
+ };
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `Box(_, _)` not covered
+ --> $DIR/issue-3601.rs:30:44
+ |
+LL | box NodeKind::Element(ed) => match ed.kind {
+ | ^^^^^^^ pattern `Box(_, _)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `Box<ElementKind>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+enum Foo {
+ Bar { bar: Bar, id: usize }
+}
+
+enum Bar {
+ A, B, C, D, E, F
+}
+
+fn test(f: Foo) {
+ match f {
+ //~^ ERROR non-exhaustive patterns
+ //~| patterns
+ Foo::Bar { bar: Bar::A, .. } => (),
+ Foo::Bar { bar: Bar::B, .. } => (),
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+ --> $DIR/issue-39362.rs:10:11
+ |
+LL | / enum Foo {
+LL | | Bar { bar: Bar, id: usize }
+LL | | }
+ | |_- `Foo` defined here
+...
+LL | match f {
+ | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+enum P {
+ C(PC),
+}
+
+enum PC {
+ Q,
+ QA,
+}
+
+fn test(proto: P) {
+ match proto { //~ ERROR non-exhaustive patterns
+ P::C(PC::Q) => (),
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `C(QA)` not covered
+ --> $DIR/issue-40221.rs:11:11
+ |
+LL | / enum P {
+LL | | C(PC),
+ | | - not covered
+LL | | }
+ | |_- `P` defined here
+...
+LL | match proto {
+ | ^^^^^ pattern `C(QA)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `P`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+fn main() {
+ let tup = (true, true);
+ println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered
+ (false, false) => "foo",
+ (false, true) => "bar",
+ (true, true) => "baz"
+ });
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `(true, false)` not covered
+ --> $DIR/issue-4321.rs:3:31
+ |
+LL | println!("foo {:}", match tup {
+ | ^^^ pattern `(true, false)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `(bool, bool)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
+++ /dev/null
-// check-pass
-#![feature(exclusive_range_pattern)]
-#![warn(unreachable_patterns)]
-#![warn(overlapping_patterns)]
-
-fn main() {
- // These cases should generate no warning.
- match 10 {
- 1..10 => {},
- 10 => {},
- _ => {},
- }
-
- match 10 {
- 1..10 => {},
- 9..=10 => {}, //~ WARNING multiple patterns covering the same range
- _ => {},
- }
-
- match 10 {
- 1..10 => {},
- 10..=10 => {},
- _ => {},
- }
-
- // These cases should generate "unreachable pattern" warnings.
- match 10 {
- 1..10 => {},
- 9 => {}, //~ WARNING unreachable pattern
- _ => {},
- }
-
- match 10 {
- 1..10 => {},
- 8..=9 => {}, //~ WARNING unreachable pattern
- _ => {},
- }
-
- match 10 {
- 5..7 => {},
- 6 => {}, //~ WARNING unreachable pattern
- 1..10 => {},
- 9..=9 => {}, //~ WARNING unreachable pattern
- 6 => {}, //~ WARNING unreachable pattern
- _ => {},
- }
-}
+++ /dev/null
-warning: multiple patterns covering the same range
- --> $DIR/issue-43253.rs:16:9
- |
-LL | 1..10 => {},
- | ----- this range overlaps on `9_i32`
-LL | 9..=10 => {},
- | ^^^^^^ overlapping patterns
- |
-note: the lint level is defined here
- --> $DIR/issue-43253.rs:4:9
- |
-LL | #![warn(overlapping_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-warning: unreachable pattern
- --> $DIR/issue-43253.rs:29:9
- |
-LL | 9 => {},
- | ^
- |
-note: the lint level is defined here
- --> $DIR/issue-43253.rs:3:9
- |
-LL | #![warn(unreachable_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-warning: unreachable pattern
- --> $DIR/issue-43253.rs:35:9
- |
-LL | 8..=9 => {},
- | ^^^^^
-
-warning: unreachable pattern
- --> $DIR/issue-43253.rs:41:9
- |
-LL | 6 => {},
- | ^
-
-warning: unreachable pattern
- --> $DIR/issue-43253.rs:43:9
- |
-LL | 9..=9 => {},
- | ^^^^^
-
-warning: unreachable pattern
- --> $DIR/issue-43253.rs:44:9
- |
-LL | 6 => {},
- | ^
-
-warning: 6 warnings emitted
-
--- /dev/null
+#[derive(PartialEq, Eq)]
+pub struct Tag(pub Context, pub u16);
+
+#[derive(PartialEq, Eq)]
+pub enum Context {
+ Tiff,
+ Exif,
+}
+
+impl Tag {
+ const ExifIFDPointer: Tag = Tag(Context::Tiff, 34665);
+}
+
+fn main() {
+ match Tag::ExifIFDPointer {
+ //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered
+ Tag::ExifIFDPointer => {}
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
+ --> $DIR/issue-50900.rs:15:11
+ |
+LL | pub struct Tag(pub Context, pub u16);
+ | ------------------------------------- `Tag` defined here
+...
+LL | match Tag::ExifIFDPointer {
+ | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `Tag`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#![crate_type="lib"]
+#![deny(unreachable_patterns)]
+
+mod test_struct {
+ // Test the exact copy of the minimal example
+ // posted in the issue.
+ pub struct Punned {
+ foo: [u8; 1],
+ bar: [u8; 1],
+ }
+
+ pub fn test(punned: Punned) {
+ match punned {
+ Punned { foo: [_], .. } => println!("foo"),
+ Punned { bar: [_], .. } => println!("bar"),
+ //~^ ERROR unreachable pattern [unreachable_patterns]
+ }
+ }
+}
+
+mod test_union {
+ // Test the same thing using a union.
+ pub union Punned {
+ foo: [u8; 1],
+ bar: [u8; 1],
+ }
+
+ pub fn test(punned: Punned) {
+ match punned {
+ Punned { foo: [_] } => println!("foo"),
+ Punned { bar: [_] } => println!("bar"),
+ //~^ ERROR unreachable pattern [unreachable_patterns]
+ }
+ }
+}
--- /dev/null
+error: unreachable pattern
+ --> $DIR/issue-57472.rs:15:13
+ |
+LL | Punned { bar: [_], .. } => println!("bar"),
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-57472.rs:2:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/issue-57472.rs:31:13
+ |
+LL | Punned { bar: [_] } => println!("bar"),
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// check-pass
+
+#![allow(unreachable_patterns)]
+
+fn main() {
+ const CONST: &[Option<()>; 1] = &[Some(())];
+ match &[Some(())] {
+ &[None] => {}
+ CONST => {}
+ &[Some(())] => {}
+ }
+}
+++ /dev/null
-#![deny(unreachable_patterns, overlapping_patterns)]
-
-fn main() {
- match 5 {
- 1 ..= 10 => { }
- 5 ..= 6 => { }
- //~^ ERROR unreachable pattern
- _ => {}
- };
-
- match 5 {
- 3 ..= 6 => { }
- 4 ..= 6 => { }
- //~^ ERROR unreachable pattern
- _ => {}
- };
-
- match 5 {
- 4 ..= 6 => { }
- 4 ..= 6 => { }
- //~^ ERROR unreachable pattern
- _ => {}
- };
-
- match 'c' {
- 'A' ..= 'z' => {}
- 'a' ..= 'z' => {}
- //~^ ERROR unreachable pattern
- _ => {}
- };
-
- match 1.0f64 {
- 0.01f64 ..= 6.5f64 => {}
- //~^ WARNING floating-point types cannot be used in patterns
- //~| WARNING floating-point types cannot be used in patterns
- //~| WARNING floating-point types cannot be used in patterns
- //~| WARNING floating-point types cannot be used in patterns
- //~| WARNING this was previously accepted by the compiler
- //~| WARNING this was previously accepted by the compiler
- //~| WARNING this was previously accepted by the compiler
- //~| WARNING this was previously accepted by the compiler
- 0.02f64 => {} //~ ERROR unreachable pattern
- //~^ WARNING floating-point types cannot be used in patterns
- //~| WARNING floating-point types cannot be used in patterns
- //~| WARNING this was previously accepted by the compiler
- //~| WARNING this was previously accepted by the compiler
- _ => {}
- };
-}
+++ /dev/null
-error: unreachable pattern
- --> $DIR/match-range-fail-dominate.rs:6:7
- |
-LL | 5 ..= 6 => { }
- | ^^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/match-range-fail-dominate.rs:1:9
- |
-LL | #![deny(unreachable_patterns, overlapping_patterns)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
- --> $DIR/match-range-fail-dominate.rs:13:7
- |
-LL | 4 ..= 6 => { }
- | ^^^^^^^
-
-error: unreachable pattern
- --> $DIR/match-range-fail-dominate.rs:20:7
- |
-LL | 4 ..= 6 => { }
- | ^^^^^^^
-
-error: unreachable pattern
- --> $DIR/match-range-fail-dominate.rs:27:7
- |
-LL | 'a' ..= 'z' => {}
- | ^^^^^^^^^^^
-
-warning: floating-point types cannot be used in patterns
- --> $DIR/match-range-fail-dominate.rs:33:7
- |
-LL | 0.01f64 ..= 6.5f64 => {}
- | ^^^^^^^
- |
- = note: `#[warn(illegal_floating_point_literal_pattern)]` 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 #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-warning: floating-point types cannot be used in patterns
- --> $DIR/match-range-fail-dominate.rs:33:19
- |
-LL | 0.01f64 ..= 6.5f64 => {}
- | ^^^^^^
- |
- = 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 #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-warning: floating-point types cannot be used in patterns
- --> $DIR/match-range-fail-dominate.rs:42:7
- |
-LL | 0.02f64 => {}
- | ^^^^^^^
- |
- = 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 #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: unreachable pattern
- --> $DIR/match-range-fail-dominate.rs:42:7
- |
-LL | 0.02f64 => {}
- | ^^^^^^^
-
-warning: floating-point types cannot be used in patterns
- --> $DIR/match-range-fail-dominate.rs:33:7
- |
-LL | 0.01f64 ..= 6.5f64 => {}
- | ^^^^^^^
- |
- = 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 #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-warning: floating-point types cannot be used in patterns
- --> $DIR/match-range-fail-dominate.rs:33:19
- |
-LL | 0.01f64 ..= 6.5f64 => {}
- | ^^^^^^
- |
- = 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 #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-warning: floating-point types cannot be used in patterns
- --> $DIR/match-range-fail-dominate.rs:42:7
- |
-LL | 0.02f64 => {}
- | ^^^^^^^
- |
- = 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 #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: aborting due to 5 previous errors; 6 warnings emitted
-
+++ /dev/null
-#![allow(illegal_floating_point_literal_pattern)]
-#![deny(unreachable_patterns)]
-
-fn main() {
- match 0.0 {
- 0.0..=1.0 => {}
- _ => {} // ok
- }
-
- match 0.0 { //~ ERROR non-exhaustive patterns
- 0.0..=1.0 => {}
- }
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `_` not covered
- --> $DIR/non-exhaustive-float-range-match.rs:10:11
- |
-LL | match 0.0 {
- | ^^^ pattern `_` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `f64`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
+++ /dev/null
-use std::{usize, isize};
-
-fn main() {
- match 0usize {
- //~^ ERROR non-exhaustive patterns
- //~| NOTE pattern `_` not covered
- //~| NOTE the matched value is of type `usize`
- //~| NOTE `usize` does not have a fixed maximum value
- 0 ..= usize::MAX => {}
- }
-
- match 0isize {
- //~^ ERROR non-exhaustive patterns
- //~| NOTE pattern `_` not covered
- //~| NOTE the matched value is of type `isize`
- //~| NOTE `isize` does not have a fixed maximum value
- isize::MIN ..= isize::MAX => {}
- }
-
- match 7usize {}
- //~^ ERROR non-exhaustive patterns
- //~| NOTE the matched value is of type `usize`
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `_` not covered
- --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:4:11
- |
-LL | match 0usize {
- | ^^^^^^ pattern `_` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `usize`
- = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
- = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-
-error[E0004]: non-exhaustive patterns: `_` not covered
- --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:12:11
- |
-LL | match 0isize {
- | ^^^^^^ pattern `_` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `isize`
- = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
- = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-
-error[E0004]: non-exhaustive patterns: type `usize` is non-empty
- --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:20:11
- |
-LL | match 7usize {}
- | ^^^^^^
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `usize`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+#[deny(unreachable_patterns)]
+
+fn parse_data1(data: &[u8]) -> u32 {
+ match data {
+ b"" => 1,
+ _ => 2,
+ }
+}
+
+fn parse_data2(data: &[u8]) -> u32 {
+ match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered
+ b"" => 1,
+ }
+}
+
+fn parse_data3(data: &[u8; 0]) -> u8 {
+ match data {
+ b"" => 1,
+ }
+}
+
+fn parse_data4(data: &[u8]) -> u8 {
+ match data { //~ ERROR non-exhaustive patterns
+ b"aaa" => 0,
+ [_, _, _] => 1,
+ }
+}
+
+fn parse_data5(data: &[u8; 3]) -> u8 {
+ match data {
+ b"aaa" => 0,
+ [_, _, _] => 1,
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
+ --> $DIR/type_polymorphic_byte_str_literals.rs:11:11
+ |
+LL | match data {
+ | ^^^^ pattern `&[_, ..]` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `&[u8]`
+
+error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
+ --> $DIR/type_polymorphic_byte_str_literals.rs:23:11
+ |
+LL | match data {
+ | ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `&[u8]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+// Ensure that auto trait checks `T` when it encounters a `PhantomData<T>` field, instead of
+// checking the `PhantomData<T>` type itself (which almost always implements an auto trait).
+
+#![feature(auto_traits)]
+
+use std::marker::{PhantomData};
+
+unsafe auto trait Zen {}
+
+unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {}
+
+struct Guard<'a, T: 'a> {
+ _marker: PhantomData<&'a T>,
+}
+
+struct Nested<T>(T);
+
+fn is_zen<T: Zen>(_: T) {}
+
+fn not_sync<T>(x: Guard<T>) {
+ is_zen(x)
+ //~^ ERROR `T` cannot be shared between threads safely [E0277]
+}
+
+fn nested_not_sync<T>(x: Nested<Guard<T>>) {
+ is_zen(x)
+ //~^ ERROR `T` cannot be shared between threads safely [E0277]
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: `T` cannot be shared between threads safely
+ --> $DIR/phantom-auto-trait.rs:21:12
+ |
+LL | fn is_zen<T: Zen>(_: T) {}
+ | --- required by this bound in `is_zen`
+...
+LL | is_zen(x)
+ | ^ `T` cannot be shared between threads safely
+ |
+ = note: required because of the requirements on the impl of `Zen` for `&T`
+ = note: required because it appears within the type `PhantomData<&T>`
+ = note: required because it appears within the type `Guard<'_, T>`
+help: consider restricting type parameter `T`
+ |
+LL | fn not_sync<T: Sync>(x: Guard<T>) {
+ | ^^^^^^
+
+error[E0277]: `T` cannot be shared between threads safely
+ --> $DIR/phantom-auto-trait.rs:26:12
+ |
+LL | fn is_zen<T: Zen>(_: T) {}
+ | --- required by this bound in `is_zen`
+...
+LL | is_zen(x)
+ | ^ `T` cannot be shared between threads safely
+ |
+ = note: required because of the requirements on the impl of `Zen` for `&T`
+ = note: required because it appears within the type `PhantomData<&T>`
+ = note: required because it appears within the type `Guard<'_, T>`
+ = note: required because it appears within the type `Nested<Guard<'_, T>>`
+help: consider restricting type parameter `T`
+ |
+LL | fn nested_not_sync<T: Sync>(x: Nested<Guard<T>>) {
+ | ^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-// Ensure that OIBIT checks `T` when it encounters a `PhantomData<T>` field, instead of checking
-// the `PhantomData<T>` type itself (which almost always implements an auto trait)
-
-#![feature(optin_builtin_traits)]
-
-use std::marker::{PhantomData};
-
-unsafe auto trait Zen {}
-
-unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {}
-
-struct Guard<'a, T: 'a> {
- _marker: PhantomData<&'a T>,
-}
-
-struct Nested<T>(T);
-
-fn is_zen<T: Zen>(_: T) {}
-
-fn not_sync<T>(x: Guard<T>) {
- is_zen(x)
- //~^ ERROR `T` cannot be shared between threads safely [E0277]
-}
-
-fn nested_not_sync<T>(x: Nested<Guard<T>>) {
- is_zen(x)
- //~^ ERROR `T` cannot be shared between threads safely [E0277]
-}
-
-fn main() {}
+++ /dev/null
-error[E0277]: `T` cannot be shared between threads safely
- --> $DIR/phantom-oibit.rs:21:12
- |
-LL | fn is_zen<T: Zen>(_: T) {}
- | --- required by this bound in `is_zen`
-...
-LL | is_zen(x)
- | ^ `T` cannot be shared between threads safely
- |
- = note: required because of the requirements on the impl of `Zen` for `&T`
- = note: required because it appears within the type `PhantomData<&T>`
- = note: required because it appears within the type `Guard<'_, T>`
-help: consider restricting type parameter `T`
- |
-LL | fn not_sync<T: Sync>(x: Guard<T>) {
- | ^^^^^^
-
-error[E0277]: `T` cannot be shared between threads safely
- --> $DIR/phantom-oibit.rs:26:12
- |
-LL | fn is_zen<T: Zen>(_: T) {}
- | --- required by this bound in `is_zen`
-...
-LL | is_zen(x)
- | ^ `T` cannot be shared between threads safely
- |
- = note: required because of the requirements on the impl of `Zen` for `&T`
- = note: required because it appears within the type `PhantomData<&T>`
- = note: required because it appears within the type `Guard<'_, T>`
- = note: required because it appears within the type `Nested<Guard<'_, T>>`
-help: consider restricting type parameter `T`
- |
-LL | fn nested_not_sync<T: Sync>(x: Nested<Guard<T>>) {
- | ^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-// normalize-stderr-32bit: "-2147483648isize" -> "$$ISIZE_MIN"
-// normalize-stderr-64bit: "-9223372036854775808isize" -> "$$ISIZE_MIN"
-// normalize-stderr-32bit: "2147483647isize" -> "$$ISIZE_MAX"
-// normalize-stderr-64bit: "9223372036854775807isize" -> "$$ISIZE_MAX"
-// normalize-stderr-32bit: "4294967295usize" -> "$$USIZE_MAX"
-// normalize-stderr-64bit: "18446744073709551615usize" -> "$$USIZE_MAX"
-
-#![feature(precise_pointer_size_matching)]
-#![feature(exclusive_range_pattern)]
-
-#![deny(unreachable_patterns, overlapping_patterns)]
-
-use std::{usize, isize};
-
-fn main() {
- match 0isize {
- isize::MIN ..= isize::MAX => {} // ok
- }
-
- match 0usize {
- 0 ..= usize::MAX => {} // ok
- }
-
- match 0isize { //~ ERROR non-exhaustive patterns
- 1 ..= 8 => {}
- -5 ..= 20 => {}
- }
-
- match 0usize { //~ ERROR non-exhaustive patterns
- 1 ..= 8 => {}
- 5 ..= 20 => {}
- }
-}
+++ /dev/null
-error[E0004]: non-exhaustive patterns: `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered
- --> $DIR/precise_pointer_size_matching.rs:24:11
- |
-LL | match 0isize {
- | ^^^^^^ patterns `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `isize`
-
-error[E0004]: non-exhaustive patterns: `0_usize` and `21_usize..=usize::MAX` not covered
- --> $DIR/precise_pointer_size_matching.rs:29:11
- |
-LL | match 0usize {
- | ^^^^^^ patterns `0_usize` and `21_usize..=usize::MAX` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `usize`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
#![allow(dead_code)]
// (#55495: The --error-format is to sidestep an issue in our test harness)
-// compile-flags: --error-format human -Z print-fuel=foo
-// build-pass (FIXME(62277): could be check-pass?)
+// compile-flags: -C opt-level=0 --error-format human -Z print-fuel=foo
+// check-pass
struct S1(u8, u16, u8);
struct S2(u8, u16, u8);
// run-pass
-// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
// ignore-sgx no processes
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
#[allow(private_in_public)]
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
pub trait PubPrincipal {}
--- /dev/null
+// aux-build:attr-stmt-expr.rs
+// aux-build:test-macros.rs
+// compile-flags: -Z span-debug
+// check-pass
+
+#![feature(proc_macro_hygiene)]
+#![feature(stmt_expr_attributes)]
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+extern crate attr_stmt_expr;
+extern crate test_macros;
+use attr_stmt_expr::{expect_let, expect_my_macro_stmt, expect_expr, expect_my_macro_expr};
+use test_macros::print_attr;
+
+// We don't use `std::println` so that we avoid loading hygiene
+// information from libstd, which would affect the SyntaxContext ids
+macro_rules! my_macro {
+ ($($tt:tt)*) => { () }
+}
+
+
+fn print_str(string: &'static str) {
+ // macros are handled a bit differently
+ #[expect_my_macro_expr]
+ my_macro!("{}", string)
+}
+
+macro_rules! make_stmt {
+ ($stmt:stmt) => {
+ #[print_attr]
+ #[rustc_dummy]
+ $stmt; // This semicolon is *not* passed to the macro,
+ // since `$stmt` is already a statement.
+ }
+}
+
+macro_rules! second_make_stmt {
+ ($stmt:stmt) => {
+ make_stmt!($stmt);
+ }
+}
+
+// The macro will see a semicolon here
+#[print_attr]
+struct ItemWithSemi;
+
+
+fn main() {
+ make_stmt!(struct Foo {});
+
+ #[print_attr]
+ #[expect_let]
+ let string = "Hello, world!";
+
+ #[print_attr]
+ #[expect_my_macro_stmt]
+ my_macro!("{}", string);
+
+ #[print_attr]
+ second_make_stmt!(#[allow(dead_code)] struct Bar {});
+
+ #[print_attr]
+ #[rustc_dummy]
+ struct Other {};
+
+ // The macro also sees a semicolon,
+ // for consistency with the `ItemWithSemi` case above.
+ #[print_attr]
+ #[rustc_dummy]
+ struct NonBracedStruct;
+
+ #[expect_expr]
+ print_str("string")
+}
--- /dev/null
+PRINT-ATTR INPUT (DISPLAY): struct ItemWithSemi ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "struct",
+ span: $DIR/allowed-attr-stmt-expr.rs:49:1: 49:7 (#0),
+ },
+ Ident {
+ ident: "ItemWithSemi",
+ span: $DIR/allowed-attr-stmt-expr.rs:49:8: 49:20 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:49:20: 49:21 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:35:9: 35:10 (#11),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/allowed-attr-stmt-expr.rs:35:11: 35:22 (#11),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:35:10: 35:23 (#11),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/allowed-attr-stmt-expr.rs:53:16: 53:22 (#0),
+ },
+ Ident {
+ ident: "Foo",
+ span: $DIR/allowed-attr-stmt-expr.rs:53:23: 53:26 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/allowed-attr-stmt-expr.rs:53:27: 53:29 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[expect_let] let string = "Hello, world!" ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:56:5: 56:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "expect_let",
+ span: $DIR/allowed-attr-stmt-expr.rs:56:7: 56:17 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:56:6: 56:18 (#0),
+ },
+ Ident {
+ ident: "let",
+ span: $DIR/allowed-attr-stmt-expr.rs:57:5: 57:8 (#0),
+ },
+ Ident {
+ ident: "string",
+ span: $DIR/allowed-attr-stmt-expr.rs:57:9: 57:15 (#0),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:57:16: 57:17 (#0),
+ },
+ Literal {
+ kind: Str,
+ symbol: "Hello, world!",
+ suffix: None,
+ span: $DIR/allowed-attr-stmt-expr.rs:57:18: 57:33 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:57:33: 57:34 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[expect_my_macro_stmt] my_macro ! ("{}", string) ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:60:5: 60:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "expect_my_macro_stmt",
+ span: $DIR/allowed-attr-stmt-expr.rs:60:7: 60:27 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:60:6: 60:28 (#0),
+ },
+ Ident {
+ ident: "my_macro",
+ span: $DIR/allowed-attr-stmt-expr.rs:61:5: 61:13 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:61:13: 61:14 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Literal {
+ kind: Str,
+ symbol: "{}",
+ suffix: None,
+ span: $DIR/allowed-attr-stmt-expr.rs:61:15: 61:19 (#0),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:61:19: 61:20 (#0),
+ },
+ Ident {
+ ident: "string",
+ span: $DIR/allowed-attr-stmt-expr.rs:61:21: 61:27 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:61:14: 61:28 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:61:28: 61:29 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): second_make_stmt ! (#[allow(dead_code)] struct Bar { }) ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "second_make_stmt",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:5: 64:21 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:64:21: 64:22 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:64:23: 64:24 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:25: 64:30 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "dead_code",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:31: 64:40 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:64:30: 64:41 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:64:24: 64:42 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:43: 64:49 (#0),
+ },
+ Ident {
+ ident: "Bar",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:50: 64:53 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/allowed-attr-stmt-expr.rs:64:54: 64:56 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:64:22: 64:57 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:64:57: 64:58 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:35:9: 35:10 (#32),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/allowed-attr-stmt-expr.rs:35:11: 35:22 (#32),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:35:10: 35:23 (#32),
+ },
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:64:23: 64:24 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:25: 64:30 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "dead_code",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:31: 64:40 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:64:30: 64:41 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:64:24: 64:42 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:43: 64:49 (#0),
+ },
+ Ident {
+ ident: "Bar",
+ span: $DIR/allowed-attr-stmt-expr.rs:64:50: 64:53 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/allowed-attr-stmt-expr.rs:64:54: 64:56 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:67:5: 67:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/allowed-attr-stmt-expr.rs:67:7: 67:18 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:67:6: 67:19 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/allowed-attr-stmt-expr.rs:68:5: 68:11 (#0),
+ },
+ Ident {
+ ident: "Other",
+ span: $DIR/allowed-attr-stmt-expr.rs:68:12: 68:17 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/allowed-attr-stmt-expr.rs:68:18: 68:20 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct NonBracedStruct ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:73:5: 73:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/allowed-attr-stmt-expr.rs:73:7: 73:18 (#0),
+ },
+ ],
+ span: $DIR/allowed-attr-stmt-expr.rs:73:6: 73:19 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/allowed-attr-stmt-expr.rs:74:5: 74:11 (#0),
+ },
+ Ident {
+ ident: "NonBracedStruct",
+ span: $DIR/allowed-attr-stmt-expr.rs:74:12: 74:27 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/allowed-attr-stmt-expr.rs:74:27: 74:28 (#0),
+ },
+]
// aux-build:attr-stmt-expr.rs
+// aux-build:test-macros.rs
+// compile-flags: -Z span-debug
#![feature(proc_macro_hygiene)]
+#![feature(rustc_attrs)]
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+extern crate test_macros;
extern crate attr_stmt_expr;
-use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr};
+
+use test_macros::print_attr;
+use attr_stmt_expr::{expect_let, expect_my_macro_stmt, expect_expr, expect_my_macro_expr};
+
+// We don't use `std::println` so that we avoid loading hygiene
+// information from libstd, which would affect the SyntaxContext ids
+macro_rules! my_macro {
+ ($($tt:tt)*) => { () }
+}
fn print_str(string: &'static str) {
// macros are handled a bit differently
- #[expect_print_expr]
+ #[expect_my_macro_expr]
//~^ ERROR attributes on expressions are experimental
//~| HELP add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
- println!("{}", string)
+ my_macro!("{}", string)
+}
+
+macro_rules! make_stmt {
+ ($stmt:stmt) => {
+ #[print_attr]
+ #[rustc_dummy]
+ $stmt
+ }
+}
+
+macro_rules! second_make_stmt {
+ ($stmt:stmt) => {
+ make_stmt!($stmt);
+ }
}
fn main() {
+ make_stmt!(struct Foo {});
+
+ #[print_attr]
#[expect_let]
let string = "Hello, world!";
- #[expect_print_stmt]
- println!("{}", string);
+ #[print_attr]
+ #[expect_my_macro_stmt]
+ my_macro!("{}", string);
+
+ #[print_attr]
+ second_make_stmt!(#[allow(dead_code)] struct Bar {});
+
+ #[print_attr]
+ #[rustc_dummy]
+ struct Other {}
#[expect_expr]
//~^ ERROR attributes on expressions are experimental
error[E0658]: attributes on expressions are experimental
- --> $DIR/attr-stmt-expr.rs:10:5
+ --> $DIR/attr-stmt-expr.rs:24:5
|
-LL | #[expect_print_expr]
- | ^^^^^^^^^^^^^^^^^^^^
+LL | #[expect_my_macro_expr]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
error[E0658]: attributes on expressions are experimental
- --> $DIR/attr-stmt-expr.rs:23:5
+ --> $DIR/attr-stmt-expr.rs:62:5
|
LL | #[expect_expr]
| ^^^^^^^^^^^^^^
--- /dev/null
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:33:9: 33:10 (#8),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/attr-stmt-expr.rs:33:11: 33:22 (#8),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:33:10: 33:23 (#8),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/attr-stmt-expr.rs:45:16: 45:22 (#0),
+ },
+ Ident {
+ ident: "Foo",
+ span: $DIR/attr-stmt-expr.rs:45:23: 45:26 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/attr-stmt-expr.rs:45:27: 45:29 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[expect_let] let string = "Hello, world!" ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:48:5: 48:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "expect_let",
+ span: $DIR/attr-stmt-expr.rs:48:7: 48:17 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:48:6: 48:18 (#0),
+ },
+ Ident {
+ ident: "let",
+ span: $DIR/attr-stmt-expr.rs:49:5: 49:8 (#0),
+ },
+ Ident {
+ ident: "string",
+ span: $DIR/attr-stmt-expr.rs:49:9: 49:15 (#0),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:49:16: 49:17 (#0),
+ },
+ Literal {
+ kind: Str,
+ symbol: "Hello, world!",
+ suffix: None,
+ span: $DIR/attr-stmt-expr.rs:49:18: 49:33 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:49:33: 49:34 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[expect_my_macro_stmt] my_macro ! ("{}", string) ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:52:5: 52:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "expect_my_macro_stmt",
+ span: $DIR/attr-stmt-expr.rs:52:7: 52:27 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:52:6: 52:28 (#0),
+ },
+ Ident {
+ ident: "my_macro",
+ span: $DIR/attr-stmt-expr.rs:53:5: 53:13 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:53:13: 53:14 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Literal {
+ kind: Str,
+ symbol: "{}",
+ suffix: None,
+ span: $DIR/attr-stmt-expr.rs:53:15: 53:19 (#0),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:53:19: 53:20 (#0),
+ },
+ Ident {
+ ident: "string",
+ span: $DIR/attr-stmt-expr.rs:53:21: 53:27 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:53:14: 53:28 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:53:28: 53:29 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): second_make_stmt ! (#[allow(dead_code)] struct Bar { }) ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "second_make_stmt",
+ span: $DIR/attr-stmt-expr.rs:56:5: 56:21 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:56:21: 56:22 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:56:23: 56:24 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: $DIR/attr-stmt-expr.rs:56:25: 56:30 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "dead_code",
+ span: $DIR/attr-stmt-expr.rs:56:31: 56:40 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:56:30: 56:41 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:56:24: 56:42 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/attr-stmt-expr.rs:56:43: 56:49 (#0),
+ },
+ Ident {
+ ident: "Bar",
+ span: $DIR/attr-stmt-expr.rs:56:50: 56:53 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/attr-stmt-expr.rs:56:54: 56:56 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:56:22: 56:57 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:56:57: 56:58 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:33:9: 33:10 (#29),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/attr-stmt-expr.rs:33:11: 33:22 (#29),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:33:10: 33:23 (#29),
+ },
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:56:23: 56:24 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: $DIR/attr-stmt-expr.rs:56:25: 56:30 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "dead_code",
+ span: $DIR/attr-stmt-expr.rs:56:31: 56:40 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:56:30: 56:41 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:56:24: 56:42 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/attr-stmt-expr.rs:56:43: 56:49 (#0),
+ },
+ Ident {
+ ident: "Bar",
+ span: $DIR/attr-stmt-expr.rs:56:50: 56:53 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/attr-stmt-expr.rs:56:54: 56:56 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attr-stmt-expr.rs:59:5: 59:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/attr-stmt-expr.rs:59:7: 59:18 (#0),
+ },
+ ],
+ span: $DIR/attr-stmt-expr.rs:59:6: 59:19 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/attr-stmt-expr.rs:60:5: 60:11 (#0),
+ },
+ Ident {
+ ident: "Other",
+ span: $DIR/attr-stmt-expr.rs:60:12: 60:17 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: $DIR/attr-stmt-expr.rs:60:18: 60:20 (#0),
+ },
+]
}
#[proc_macro_attribute]
-pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream {
+pub fn expect_my_macro_stmt(attr: TokenStream, item: TokenStream) -> TokenStream {
assert!(attr.to_string().is_empty());
- assert_eq!(item.to_string(), "println ! (\"{}\", string) ;");
+ assert_eq!(item.to_string(), "my_macro ! (\"{}\", string) ;");
item
}
}
#[proc_macro_attribute]
-pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream {
+pub fn expect_my_macro_expr(attr: TokenStream, item: TokenStream) -> TokenStream {
assert!(attr.to_string().is_empty());
- assert_eq!(item.to_string(), "println ! (\"{}\", string)");
+ assert_eq!(item.to_string(), "my_macro ! (\"{}\", string)");
item
}
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn dummy(input: TokenStream) -> TokenStream {
+ // Iterate to force internal conversion of nonterminals
+ // to `proc_macro` structs
+ for _ in input {}
+ TokenStream::new()
+}
--- /dev/null
+// check-pass
+// aux-build:issue-79242.rs
+
+// Regression test for issue #79242
+// Tests that compilation time doesn't blow up for a proc-macro
+// invocation with deeply nested nonterminals
+
+#![allow(unused)]
+
+extern crate issue_79242;
+
+macro_rules! declare_nats {
+ ($prev:ty) => {};
+ ($prev:ty, $n:literal$(, $tail:literal)*) => {
+
+ issue_79242::dummy! {
+ $prev
+ }
+
+ declare_nats!(Option<$prev>$(, $tail)*);
+ };
+ (0, $($n:literal),+) => {
+ pub struct N0;
+ declare_nats!(N0, $($n),+);
+ };
+}
+
+declare_nats! {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28
+}
+
+
+fn main() {}
// aux-build:test-macros.rs
+// compile-flags: -Z span-debug
#![feature(stmt_expr_attributes)]
#![feature(proc_macro_hygiene)]
+#![feature(rustc_attrs)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
extern crate test_macros;
for item in missing_fn() {} //~ ERROR cannot find
(#[recollect_attr] #[recollect_attr] ((#[recollect_attr] bad))); //~ ERROR cannot
+
+ #[test_macros::print_attr]
+ #[rustc_dummy]
+ { 1 +1; } // Don't change the weird spacing of the '+'
}
error[E0425]: cannot find function `missing_fn` in this scope
- --> $DIR/keep-expr-tokens.rs:12:17
+ --> $DIR/keep-expr-tokens.rs:17:17
|
LL | for item in missing_fn() {}
| ^^^^^^^^^^ not found in this scope
error[E0425]: cannot find value `bad` in this scope
- --> $DIR/keep-expr-tokens.rs:14:62
+ --> $DIR/keep-expr-tokens.rs:19:62
|
LL | (#[recollect_attr] #[recollect_attr] ((#[recollect_attr] bad)));
| ^^^ not found in this scope
--- /dev/null
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] { 1 + 1 ; }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/keep-expr-tokens.rs:22:5: 22:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/keep-expr-tokens.rs:22:7: 22:18 (#0),
+ },
+ ],
+ span: $DIR/keep-expr-tokens.rs:22:6: 22:19 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Literal {
+ kind: Integer,
+ symbol: "1",
+ suffix: None,
+ span: $DIR/keep-expr-tokens.rs:23:7: 23:8 (#0),
+ },
+ Punct {
+ ch: '+',
+ spacing: Alone,
+ span: $DIR/keep-expr-tokens.rs:23:9: 23:10 (#0),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "1",
+ suffix: None,
+ span: $DIR/keep-expr-tokens.rs:23:10: 23:11 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/keep-expr-tokens.rs:23:11: 23:12 (#0),
+ },
+ ],
+ span: $DIR/keep-expr-tokens.rs:23:5: 23:14 (#0),
+ },
+]
extern crate test_macros;
fn _test_inner() {
- #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable
+ #![empty_attr] //~ ERROR: inner macro attributes are unstable
}
mod _test2_inner {
- #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable
+ #![empty_attr] //~ ERROR: inner macro attributes are unstable
}
#[empty_attr = "y"] //~ ERROR: key-value macro attributes are not supported
//~^ ERROR: custom attributes cannot be applied to expressions
}
+fn test_case() {
+ #![test] //~ ERROR inner macro attributes are unstable
+ //~| WARN this was previously accepted
+}
+
fn main() {}
-error[E0658]: non-builtin inner attributes are unstable
- --> $DIR/proc-macro-gates.rs:10:5
+error[E0658]: inner macro attributes are unstable
+ --> $DIR/proc-macro-gates.rs:10:8
|
LL | #![empty_attr]
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
-error[E0658]: non-builtin inner attributes are unstable
- --> $DIR/proc-macro-gates.rs:14:5
+error[E0658]: inner macro attributes are unstable
+ --> $DIR/proc-macro-gates.rs:14:8
|
LL | #![empty_attr]
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
= note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information
= help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-error: aborting due to 9 previous errors
+error: inner macro attributes are unstable
+ --> $DIR/proc-macro-gates.rs:49:8
+ |
+LL | #![test]
+ | ^^^^
+ |
+ = note: `#[deny(soft_unstable)]` 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 #64266 <https://github.com/rust-lang/rust/issues/64266>
+
+error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0658`.
// should either require a feature gate or not be allowed on stable.
fn _test6<#[empty_attr] T>() {}
-//~^ ERROR: expected an inert attribute, found an attribute macro
+//~^ ERROR: expected non-macro attribute, found attribute macro
fn _test7() {
match 1 {
- #[empty_attr] //~ ERROR: expected an inert attribute, found an attribute macro
+ #[empty_attr] //~ ERROR: expected non-macro attribute, found attribute macro
0 => {}
_ => {}
}
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-gates2.rs:12:11
+error: expected non-macro attribute, found attribute macro `empty_attr`
+ --> $DIR/proc-macro-gates2.rs:12:13
|
LL | fn _test6<#[empty_attr] T>() {}
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-gates2.rs:17:9
+error: expected non-macro attribute, found attribute macro `empty_attr`
+ --> $DIR/proc-macro-gates2.rs:17:11
|
LL | #[empty_attr]
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^ not a non-macro attribute
error: aborting due to 2 previous errors
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-vxworks no 'env'
// run-pass
#![allow(unused_imports)]
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-vxworks no 'env'
// (instead of running forever), and that it does not print an error
// message about a broken pipe.
-// ignore-cloudabi no subprocesses support
// ignore-emscripten no threads support
// ignore-vxworks no 'sh'
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// non-ASCII characters. The child process ensures all the strings are
// intact.
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// run-fail
// error-pattern:nonzero
// exec-env:RUST_NEWRT=1
-// ignore-cloudabi no std::env
// ignore-emscripten no processes
use std::env;
--- /dev/null
+// check-pass
+
+use std as line;
+
+const C: u32 = line!();
+
+fn main() {}
-// ignore-cloudabi no std::fs support
-
// Test that we do some basic error correction in the tokeniser (and don't spew
// too many bogus errors).
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
- --> $DIR/token-error-correct-3.rs:15:35
+ --> $DIR/token-error-correct-3.rs:13:35
|
LL | callback(path.as_ref();
| - ^ help: `)` may belong here
| unclosed delimiter
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
- --> $DIR/token-error-correct-3.rs:18:9
+ --> $DIR/token-error-correct-3.rs:16:9
|
LL | fs::create_dir_all(path.as_ref()).map(|()| true)
| - expected one of `.`, `;`, `?`, `}`, or an operator
| ^ unexpected token
error[E0425]: cannot find function `is_directory` in this scope
- --> $DIR/token-error-correct-3.rs:13:13
+ --> $DIR/token-error-correct-3.rs:11:13
|
LL | if !is_directory(path.as_ref()) {
| ^^^^^^^^^^^^ not found in this scope
-// ignore-cloudabi no std::path support
-
macro_rules! y {
() => {}
}
error[E0412]: cannot find type `Path` in this scope
- --> $DIR/use_suggestion_placement.rs:17:16
+ --> $DIR/use_suggestion_placement.rs:15:16
|
LL | type Bar = Path;
| ^^^^ not found in this scope
|
error[E0425]: cannot find value `A` in this scope
- --> $DIR/use_suggestion_placement.rs:22:13
+ --> $DIR/use_suggestion_placement.rs:20:13
|
LL | let _ = A;
| ^ not found in this scope
|
error[E0412]: cannot find type `HashMap` in this scope
- --> $DIR/use_suggestion_placement.rs:27:23
+ --> $DIR/use_suggestion_placement.rs:25:23
|
LL | type Dict<K, V> = HashMap<K, V>;
| ^^^^^^^ not found in this scope
fn g() {}
}
-extern "Rust" {
- #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
- #[naked]
- fn h();
-}
-
fn main() {}
LL | #[track_caller]
| ^^^^^^^^^^^^^^^
-error[E0736]: cannot use `#[track_caller]` with `#[naked]`
- --> $DIR/error-with-naked.rs:16:5
- |
-LL | #[track_caller]
- | ^^^^^^^^^^^^^^^
-
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
--> $DIR/error-with-naked.rs:10:5
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0736`.
/// Foo
//~^ ERROR documentation comments cannot be applied to function
#[test] a: i32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Foo
//~^ ERROR documentation comments cannot be applied to function
#[test] a: u32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Foo
//~^ ERROR documentation comments cannot be applied to function
#[test] a: u32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[test] a: i32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Foo
//~^ ERROR documentation comments cannot be applied to function
#[test] a: i32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[test] a: i32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[test] a: i32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Foo
//~^ ERROR documentation comments cannot be applied to function
#[test] a: i32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[test] a: i32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
/// Foo
//~^ ERROR documentation comments cannot be applied to function
#[test] a: u32,
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:5:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:5:11
|
LL | #[test] a: i32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:21:5
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:21:7
|
LL | #[test] a: u32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:36:5
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:36:7
|
LL | #[test] a: u32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:56:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:56:11
|
LL | #[test] a: i32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:71:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:71:11
|
LL | #[test] a: i32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:92:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:92:11
|
LL | #[test] a: i32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:111:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:111:11
|
LL | #[test] a: i32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:126:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:126:11
|
LL | #[test] a: i32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:146:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:146:11
|
LL | #[test] a: i32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/param-attrs-builtin-attrs.rs:163:9
+error: expected non-macro attribute, found attribute macro `test`
+ --> $DIR/param-attrs-builtin-attrs.rs:163:11
|
LL | #[test] a: u32,
- | ^^^^^^^
+ | ^^^^ not a non-macro attribute
error: documentation comments cannot be applied to function parameters
--> $DIR/param-attrs-builtin-attrs.rs:3:9
struct W(u8);
extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
-//~^ ERROR expected an inert attribute, found an attribute macro
-//~| ERROR expected an inert attribute, found an attribute macro
+//~^ ERROR expected non-macro attribute, found attribute macro
+//~| ERROR expected non-macro attribute, found attribute macro
unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {}
-//~^ ERROR expected an inert attribute, found an attribute macro
+//~^ ERROR expected non-macro attribute, found attribute macro
type Alias = extern "C" fn(#[id] u8, #[id] ...);
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn free(#[id] arg1: u8) {
- //~^ ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
let lam = |#[id] W(x), #[id] y: usize| ();
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
}
impl W {
fn inherent1(#[id] self, #[id] arg1: u8) {}
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn inherent2(#[id] &self, #[id] arg1: u8) {}
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
}
trait A {
fn trait1(#[id] self, #[id] arg1: u8);
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn trait2(#[id] &self, #[id] arg1: u8);
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
- //~^ ERROR expected an inert attribute, found an attribute macro
- //~| ERROR expected an inert attribute, found an attribute macro
+ //~^ ERROR expected non-macro attribute, found attribute macro
+ //~| ERROR expected non-macro attribute, found attribute macro
}
fn main() {}
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:10:21
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:10:23
|
LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:10:38
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:10:40
|
LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:14:38
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:14:40
|
LL | unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:17:28
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:17:30
|
LL | type Alias = extern "C" fn(#[id] u8, #[id] ...);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:17:38
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:17:40
|
LL | type Alias = extern "C" fn(#[id] u8, #[id] ...);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:21:9
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:21:11
|
LL | fn free(#[id] arg1: u8) {
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:23:16
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:23:18
|
LL | let lam = |#[id] W(x), #[id] y: usize| ();
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:23:28
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:23:30
|
LL | let lam = |#[id] W(x), #[id] y: usize| ();
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:29:18
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:29:20
|
LL | fn inherent1(#[id] self, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:29:30
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:29:32
|
LL | fn inherent1(#[id] self, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:32:18
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:32:20
|
LL | fn inherent2(#[id] &self, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:32:31
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:32:33
|
LL | fn inherent2(#[id] &self, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:35:22
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:35:24
|
LL | fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:35:42
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:35:44
|
LL | fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:38:22
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:38:24
|
LL | fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:38:45
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:38:47
|
LL | fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:41:38
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:41:40
|
LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:41:54
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:41:56
|
LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:47:15
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:47:17
|
LL | fn trait1(#[id] self, #[id] arg1: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:47:27
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:47:29
|
LL | fn trait1(#[id] self, #[id] arg1: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:50:15
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:50:17
|
LL | fn trait2(#[id] &self, #[id] arg1: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:50:28
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:50:30
|
LL | fn trait2(#[id] &self, #[id] arg1: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:53:19
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:53:21
|
LL | fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:53:39
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:53:41
|
LL | fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:56:19
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:56:21
|
LL | fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:56:42
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:56:44
|
LL | fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:56:58
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:56:60
|
LL | fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:60:38
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:60:40
|
LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
-error: expected an inert attribute, found an attribute macro
- --> $DIR/proc-macro-cannot-be-used.rs:60:54
+error: expected non-macro attribute, found attribute macro `id`
+ --> $DIR/proc-macro-cannot-be-used.rs:60:56
|
LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
- | ^^^^^
+ | ^^ not a non-macro attribute
error: aborting due to 29 previous errors
--- /dev/null
+//! Basic test for calling methods on generic type parameters in `const fn`.
+
+// check-pass
+
+#![feature(const_fn)]
+#![feature(const_trait_impl)]
+#![allow(incomplete_features)]
+
+struct S;
+
+impl const PartialEq for S {
+ fn eq(&self, _: &S) -> bool {
+ true
+ }
+}
+
+const fn equals_self<T: PartialEq>(t: &T) -> bool {
+ *t == *t
+}
+
+const fn equals_self_wrapper<T: PartialEq>(t: &T) -> bool {
+ equals_self(t)
+}
+
+pub const EQ: bool = equals_self_wrapper(&S);
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(const_fn)]
+#![feature(const_trait_impl)]
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+struct S;
+
+impl const PartialEq for S {
+ fn eq(&self, _: &S) -> bool {
+ true
+ }
+}
+
+// This duplicate bound should not result in ambiguities. It should be equivalent to a single const
+// bound.
+const fn equals_self<T: PartialEq + ?const PartialEq>(t: &T) -> bool {
+ *t == *t
+}
+
+pub const EQ: bool = equals_self(&S);
+
+fn main() {}
--- /dev/null
+#![feature(const_fn)]
+#![feature(const_trait_impl)]
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+pub const fn equals_self<T: ?const PartialEq>(t: &T) -> bool {
+ *t == *t
+ //~^ ERROR calls in constant functions are limited to constant functions
+}
+
+fn main() {}
--- /dev/null
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/call-generic-method-fail.rs:7:5
+ |
+LL | *t == *t
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
--- /dev/null
+// check-pass
+
+#![feature(const_fn)]
+#![feature(const_trait_impl)]
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+struct S;
+
+impl PartialEq for S {
+ fn eq(&self, _: &S) -> bool {
+ true
+ }
+}
+
+const fn equals_self<T: ?const PartialEq>(t: &T) -> bool {
+ true
+}
+
+pub const EQ: bool = equals_self(&S);
+
+// Calling `equals_self` with a type that only has a non-const impl is fine, because we opted out.
+
+fn main() {}
--- /dev/null
+// FIXME(jschievink): this is not rejected correctly (only when the non-const impl is actually used)
+// ignore-test
+
+#![feature(const_fn)]
+#![feature(const_trait_impl)]
+#![allow(incomplete_features)]
+
+struct S;
+
+impl PartialEq for S {
+ fn eq(&self, _: &S) -> bool {
+ true
+ }
+}
+
+const fn equals_self<T: PartialEq>(t: &T) -> bool {
+ true
+}
+
+// Calling `equals_self` with something that has a non-const impl should throw an error, despite
+// it not using the impl.
+
+pub const EQ: bool = equals_self(&S);
+//~^ ERROR
+
+fn main() {}
--- /dev/null
+//! Basic test for calling methods on generic type parameters in `const fn`.
+
+// check-pass
+
+#![feature(const_fn)]
+#![feature(const_trait_impl)]
+#![allow(incomplete_features)]
+
+struct S;
+
+impl const PartialEq for S {
+ fn eq(&self, _: &S) -> bool {
+ true
+ }
+}
+
+const fn equals_self<T: PartialEq>(t: &T) -> bool {
+ *t == *t
+}
+
+pub const EQ: bool = equals_self(&S);
+
+fn main() {}
// run-pass
#![allow(dead_code)]
-// ignore-cloudabi stdout does not map to file descriptor 1 by default
// ignore-wasm32-bare no libc
// ignore-sgx no libc
// run-pass
-// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
// ignore-sgx no processes
// main thread exit while still being in use by signal handlers. This test
// triggers this situation by sending signal from atexit handler.
//
-// ignore-cloudabi no signal handling support
// ignore-wasm32-bare no libc
// ignore-windows
// ignore-sgx no libc
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-windows
// Be sure that when a SIGPIPE would have been received that the entire process
// doesn't die in a ball of fire, but rather it's gracefully handled.
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
-// ignore-cloudabi no std::net support
-
use std::net::TcpListener;
use std::net::TcpStream;
use std::io::{self, Read, Write};
error[E0308]: mismatched types
- --> $DIR/issue-33884.rs:8:22
+ --> $DIR/issue-33884.rs:6:22
|
LL | stream.write_fmt(format!("message received"))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Arguments`, found struct `String`
#[foo]
mod foo {
- #![foo] //~ ERROR non-builtin inner attributes are unstable
+ #![foo] //~ ERROR custom inner attributes are unstable
}
fn main() {}
-error[E0658]: non-builtin inner attributes are unstable
- --> $DIR/issue-36530.rs:9:5
+error[E0658]: custom inner attributes are unstable
+ --> $DIR/issue-36530.rs:9:8
|
LL | #![foo]
- | ^^^^^^^
+ | ^^^
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
//~| ERROR cannot determine resolution for the derive macro `Debug`
//~| ERROR cannot determine resolution for the derive macro `PartialEq`
//~| ERROR cannot determine resolution for the derive macro `Eq`
-//~| ERROR cannot determine resolution for the derive macro `Debug`
-//~| ERROR cannot determine resolution for the derive macro `PartialEq`
-//~| ERROR cannot determine resolution for the derive macro `Eq`
struct DerivedOn;
fn main() {}
|
= note: import resolution is stuck, try simplifying macro imports
-error: cannot determine resolution for the derive macro `Eq`
- --> $DIR/issue-43927-non-ADT-derive.rs:3:29
- |
-LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
- | ^^
- |
- = note: import resolution is stuck, try simplifying macro imports
-
-error: cannot determine resolution for the derive macro `PartialEq`
- --> $DIR/issue-43927-non-ADT-derive.rs:3:18
- |
-LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
- | ^^^^^^^^^
- |
- = note: import resolution is stuck, try simplifying macro imports
-
-error: cannot determine resolution for the derive macro `Debug`
- --> $DIR/issue-43927-non-ADT-derive.rs:3:11
- |
-LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
- | ^^^^^
- |
- = note: import resolution is stuck, try simplifying macro imports
-
-error: aborting due to 7 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0774`.
// Make sure specialization cannot change impl polarity
-#![feature(optin_builtin_traits)]
+#![feature(auto_traits)]
#![feature(negative_impls)]
#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// run-pass
-// ignore-cloudabi no std::env
#![allow(stable_features)]
#![feature(cfg_target_feature)]
// run-pass
// ignore-android FIXME #17520
-// ignore-cloudabi spawning processes is not supported
// ignore-emscripten spawning processes is not supported
// ignore-openbsd no support for libbacktrace without filename
// ignore-sgx no processes
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
pub struct Foo;
impl Foo {
pub fn foo() {
- enum Panic { Common };
+ enum Panic { Common }
}
pub fn bar() {
- enum Panic { Common };
+ enum Panic { Common }
}
}
#[cfg(any(target_os = "android",
- target_os = "cloudabi",
target_os = "dragonfly",
target_os = "emscripten",
target_os = "freebsd",
//[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-64bit: "h310ea0259fc3d32d" -> "SYMBOL_HASH"
-#![feature(optin_builtin_traits, rustc_attrs)]
+#![feature(auto_traits, rustc_attrs)]
#![allow(dead_code)]
mod foo {
// run-pass
// ignore-android needs extra network permissions
-// ignore-cloudabi no global network namespace access
// ignore-emscripten no threads or sockets support
// ignore-netbsd system ulimit (Too many open files)
// ignore-openbsd system ulimit (Too many open files)
// run-pass
-// ignore-cloudabi networking not available
// ignore-wasm32-bare networking not available
// ignore-sgx ToSocketAddrs cannot be used for DNS Resolution
--- /dev/null
+// Auto-trait-based version of #29859, supertrait version. Test that using
+// a simple auto trait `..` impl alone still doesn't allow arbitrary bounds
+// to be synthesized.
+
+#![feature(auto_traits)]
+#![feature(negative_impls)]
+
+auto trait Magic: Copy {} //~ ERROR E0568
+
+fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
+
+#[derive(Debug)]
+struct NoClone;
+
+fn main() {
+ let (a, b) = copy(NoClone); //~ ERROR
+ println!("{:?} {:?}", a, b);
+}
--- /dev/null
+error[E0568]: auto traits cannot have super traits
+ --> $DIR/traits-inductive-overflow-supertrait-auto-trait.rs:8:19
+ |
+LL | auto trait Magic: Copy {}
+ | ----- ^^^^ help: remove the super traits
+ | |
+ | auto trait cannot have super traits
+
+error[E0277]: the trait bound `NoClone: Copy` is not satisfied
+ --> $DIR/traits-inductive-overflow-supertrait-auto-trait.rs:16:23
+ |
+LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
+ | ----- required by this bound in `copy`
+...
+LL | let (a, b) = copy(NoClone);
+ | ^^^^^^^ the trait `Copy` is not implemented for `NoClone`
+ |
+ = note: required because of the requirements on the impl of `Magic` for `NoClone`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0568.
+For more information about an error, try `rustc --explain E0277`.
+++ /dev/null
-// OIBIT-based version of #29859, supertrait version. Test that using
-// a simple OIBIT `..` impl alone still doesn't allow arbitrary bounds
-// to be synthesized.
-
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Magic: Copy {} //~ ERROR E0568
-
-fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
-
-#[derive(Debug)]
-struct NoClone;
-
-fn main() {
- let (a, b) = copy(NoClone); //~ ERROR
- println!("{:?} {:?}", a, b);
-}
+++ /dev/null
-error[E0568]: auto traits cannot have super traits
- --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:8:19
- |
-LL | auto trait Magic: Copy {}
- | ----- ^^^^ help: remove the super traits
- | |
- | auto trait cannot have super traits
-
-error[E0277]: the trait bound `NoClone: Copy` is not satisfied
- --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:16:23
- |
-LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
- | ----- required by this bound in `copy`
-...
-LL | let (a, b) = copy(NoClone);
- | ^^^^^^^ the trait `Copy` is not implemented for `NoClone`
- |
- = note: required because of the requirements on the impl of `Magic` for `NoClone`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0277, E0568.
-For more information about an error, try `rustc --explain E0277`.
fn main() {
let try = 2;
- struct try { try: u32 };
+ struct try { try: u32 }
let try: try = try { try };
assert_eq!(try.try, 2);
}
-// ignore-cloudabi no std::fs support
-
#![feature(try_trait)]
use std::ops::Try;
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
- --> $DIR/try-operator-on-main.rs:9:5
+ --> $DIR/try-operator-on-main.rs:7:5
|
LL | / fn main() {
LL | | // error for a `Try` type on a non-`Try` fn
= note: required by `from_error`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/try-operator-on-main.rs:12:5
+ --> $DIR/try-operator-on-main.rs:10:5
|
LL | ()?;
| ^^^ the `?` operator cannot be applied to type `()`
= note: required by `into_result`
error[E0277]: the trait bound `(): Try` is not satisfied
- --> $DIR/try-operator-on-main.rs:15:25
+ --> $DIR/try-operator-on-main.rs:13:25
|
LL | try_trait_generic::<()>();
| ^^ the trait `Try` is not implemented for `()`
| --- required by this bound in `try_trait_generic`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/try-operator-on-main.rs:22:5
+ --> $DIR/try-operator-on-main.rs:20:5
|
LL | ()?;
| ^^^ the `?` operator cannot be applied to type `()`
// run-pass
#![allow(dead_code)]
-// ignore-cloudabi no std::fs
use std::fs::File;
use std::io::{Read, self};
// run-pass
#![allow(stable_features)]
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
input_cells: Vec::new()
//~^ ERROR cannot find value `input_cells` in this scope
//~| ERROR parenthesized type parameters may only be used with a `Fn` trait
- //~| ERROR wrong number of type arguments: expected 1, found 0
+ //~| ERROR wrong number of type arguments: expected at least 1, found 0
}
}
LL | input_cells: Vec::new()
| ^^^^^ only `Fn` traits may use parentheses
-error[E0107]: wrong number of type arguments: expected 1, found 0
+error[E0107]: wrong number of type arguments: expected at least 1, found 0
--> $DIR/issue-34255-1.rs:7:22
|
LL | input_cells: Vec::new()
- | ^^^^^^^^^^ expected 1 type argument
+ | ^^^^^^^^^^ expected at least 1 type argument
error: aborting due to 3 previous errors
-#![feature(optin_builtin_traits, core)]
+#![feature(auto_traits, core)]
#![crate_type = "rlib"]
pub auto trait DefaultedTrait { }
// run-pass
-// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-vxworks no 'ps'
}
#[cfg(any(target_os = "android",
- target_os = "cloudabi",
target_os = "dragonfly",
target_os = "emscripten",
target_os = "freebsd",
fn drop(&mut self) {
unsafe { destructions -= 1 };
}
- };
+ }
let _x = [Foo, Foo, Foo];
}
"aarch64-fuchsia",
"aarch64-linux-android",
"aarch64-pc-windows-msvc",
- "aarch64-unknown-cloudabi",
"aarch64-unknown-hermit",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"x86_64-rumprun-netbsd",
"x86_64-sun-solaris",
"x86_64-pc-solaris",
- "x86_64-unknown-cloudabi",
"x86_64-unknown-freebsd",
"x86_64-unknown-illumos",
"x86_64-unknown-linux-gnu",
-Subproject commit 2af662e22177a839763ac8fb70d245a680b15214
+Subproject commit bfca1cd22bf514d5f2b6c1089b0ded0ba7dfaa6e
Thank you for making Clippy better!
We're collecting our changelog from pull request descriptions.
-If your PR only updates to the latest nightly, you can leave the
-`changelog` entry as `none`. Otherwise, please write a short comment
+If your PR only includes internal changes, you can just write
+`changelog: none`. Otherwise, please write a short comment
explaining your change.
If your PR fixes an issue, you can add "fixes #issue_number" into this
---
-*Please keep the line below*
-changelog: none
+*Please write a short comment explaining your change (or "none" for internal only changes)*
+changelog:
## Unreleased / In Rust Nightly
-[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master)
+[b20d4c1...master](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...master)
+
+## Rust 1.49
+
+Current beta, release 2020-12-31
+
+[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
+
+### New Lints
+
+* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
+* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
+* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
+* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
+* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
+* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
+* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103)
+* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109)
+* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123)
+* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135)
+* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157)
+* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165)
+* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177)
+* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183)
+* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226)
+* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227)
+* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233)
+
+### Moves and Deprecations
+
+* Rename `single_char_push_str` to [`single_char_add_str`]
+ [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
+* Rename `zero_width_space` to [`invisible_characters`]
+ [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
+* Deprecate [`drop_bounds`] (uplifted)
+ [#6111](https://github.com/rust-lang/rust-clippy/pull/6111)
+* Move [`string_lit_as_bytes`] to `nursery`
+ [#6117](https://github.com/rust-lang/rust-clippy/pull/6117)
+* Move [`rc_buffer`] to `restriction`
+ [#6128](https://github.com/rust-lang/rust-clippy/pull/6128)
+
+### Enhancements
+
+* [`manual_memcpy`]: Also lint when there are loop counters (and produce a
+ reliable suggestion)
+ [#5727](https://github.com/rust-lang/rust-clippy/pull/5727)
+* [`single_char_add_str`]: Also lint on `String::insert_str`
+ [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
+* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}`
+ [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
+* [`eq_op`]: Also lint on the `assert_*!` macro family
+ [#6167](https://github.com/rust-lang/rust-clippy/pull/6167)
+* [`items_after_statements`]: Also lint in local macro expansions
+ [#6176](https://github.com/rust-lang/rust-clippy/pull/6176)
+* [`unnecessary_cast`]: Also lint casts on integer and float literals
+ [#6187](https://github.com/rust-lang/rust-clippy/pull/6187)
+* [`manual_unwrap_or`]: Also lint `Result::unwrap_or`
+ [#6190](https://github.com/rust-lang/rust-clippy/pull/6190)
+* [`match_like_matches_macro`]: Also lint when `match` has more than two arms
+ [#6216](https://github.com/rust-lang/rust-clippy/pull/6216)
+* [`integer_arithmetic`]: Better handle `/` an `%` operators
+ [#6229](https://github.com/rust-lang/rust-clippy/pull/6229)
+
+### False Positive Fixes
+
+* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the
+ lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978)
+* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it
+ is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076)
+* [`or_fun_call`]: Revert changes addressing the handling of `const fn`
+ [#6077](https://github.com/rust-lang/rust-clippy/pull/6077)
+* [`needless_range_loop`]: No longer lints, when the iterable is used in the
+ range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102)
+* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent
+ [#6104](https://github.com/rust-lang/rust-clippy/pull/6104)
+* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a
+ float (e.g. `713.32_64`)
+ [#6114](https://github.com/rust-lang/rust-clippy/pull/6114)
+* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex`
+ [#6132](https://github.com/rust-lang/rust-clippy/pull/6132)
+* [`boxed_local`]: No longer lints on `extern fn` arguments
+ [#6133](https://github.com/rust-lang/rust-clippy/pull/6133)
+* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where`
+ clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198)
+
+### Suggestion Fixes/Improvements
+
+* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter
+ [#6078](https://github.com/rust-lang/rust-clippy/pull/6078)
+* [`needless_arbitrary_self_type`]: Correctly handle expanded code
+ [#6093](https://github.com/rust-lang/rust-clippy/pull/6093)
+* [`useless_format`]: Preserve raw strings in suggestion
+ [#6151](https://github.com/rust-lang/rust-clippy/pull/6151)
+* [`empty_loop`]: Suggest alternatives
+ [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
+* [`borrowed_box`]: Correctly add parentheses in suggestion
+ [#6200](https://github.com/rust-lang/rust-clippy/pull/6200)
+* [`unused_unit`]: Improve suggestion formatting
+ [#6247](https://github.com/rust-lang/rust-clippy/pull/6247)
+
+### Documentation Improvements
+
+* Some doc improvements:
+ * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
+ * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
+* [`doc_markdown`]: Document problematic link text style
+ [#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
## Rust 1.48
-Current beta, release 2020-11-19
+Current stable, released 2020-11-19
[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
[#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
-* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
+* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
[#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
[#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
[#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
* [`doc_markdown`]: allow using "GraphQL" without backticks
[#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
-* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
+* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
[#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
[#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
[#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
* [`useless_conversion`]: show the type in the error message
[#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
-* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
+* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
[#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
[#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
[#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
-* [`collapsible_if`]: don't use expanded code in the suggestion
+* [`collapsible_if`]: don't use expanded code in the suggestion
[#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
[#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
* [`unit_arg`]: improve the readability of the suggestion
[#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
-* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
+* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
[#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
* Show line count and max lines in [`too_many_lines`] lint message
[#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
[#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
[#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
-* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
+* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
[#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
* Make lint messages adhere to rustc dev guide conventions
[#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
## Rust 1.47
-Current stable, released 2020-10-08
+Released 2020-10-08
[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
+[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
+[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
+[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
-We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
-
-* `clippy::all` (everything that is on by default: all the categories below except for `nursery`, `pedantic`, and `cargo`)
-* `clippy::correctness` (code that is just **outright wrong** or **very very useless**, causes hard errors by default)
-* `clippy::style` (code that should be written in a more idiomatic way)
-* `clippy::complexity` (code that does something simple but in a complex way)
-* `clippy::perf` (code that can be written in a faster way)
-* `clippy::pedantic` (lints which are rather strict, off by default)
-* `clippy::nursery` (new lints that aren't quite ready yet, off by default)
-* `clippy::cargo` (checks against the cargo manifest, off by default)
+Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
+You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
+
+Category | Description | Default level
+-- | -- | --
+`clippy::all` | all lints that are on by default (correctness, style, complexity, perf) | **warn/deny**
+`clippy::correctness` | code that is outright wrong or very useless | **deny**
+`clippy::style` | code that should be written in a more idiomatic way | **warn**
+`clippy::complexity` | code that does something simple but in a complex way | **warn**
+`clippy::perf` | code that can be written to run faster | **warn**
+`clippy::pedantic` | lints which are rather strict or might have false positives | allow
+`clippy::nursery` | new lints that are still under development | allow
+`clippy::cargo` | lints for the cargo manifest | allow
More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
-Only the following of those categories are enabled by default:
-
-* `clippy::style`
-* `clippy::correctness`
-* `clippy::complexity`
-* `clippy::perf`
-
-Other categories need to be enabled in order for their lints to be executed.
-
The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are
for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used
very selectively, if at all.
let usable_lint_count = round_to_fifty(usable_lints.len());
- let mut file_change = replace_region_in_file(
- Path::new("src/lintlist/mod.rs"),
- "begin lint list",
- "end lint list",
- false,
- update_mode == UpdateMode::Change,
- || {
- format!("vec!{:#?}", sorted_usable_lints)
- .lines()
- .map(ToString::to_string)
- .collect::<Vec<_>>()
- },
- )
- .changed;
+ let mut file_change = false;
file_change |= replace_region_in_file(
Path::new("README.md"),
if let ExprKind::Block(ref block, _) = arms[0].body.kind;
if block.stmts.is_empty();
if let Some(block_expr) = &block.expr;
- if let ExprKind::Block(ref inner_block, _) = block_expr.kind;
- if let Some(begin_panic_call) = &inner_block.expr;
+ // inner block is optional. unwrap it if it exists, or use the expression as is otherwise.
+ if let Some(begin_panic_call) = match block_expr.kind {
+ ExprKind::Block(ref inner_block, _) => &inner_block.expr,
+ _ => &block.expr,
+ };
// function call
if let Some(args) = match_panic_call(cx, begin_panic_call);
if args.len() == 1;
span_lint_and_sugg, span_lint_and_then, without_block_comments,
};
use if_chain::if_chain;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_errors::Applicability;
use rustc_hir::{
];
// NOTE: windows is excluded from the list because it's also a valid target family.
-static NON_UNIX_SYSTEMS: &[&str] = &["cloudabi", "hermit", "none", "wasi"];
+static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"];
declare_clippy_lint! {
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
.map(|l| Symbol::intern(&l.name_lower()))
.collect::<Vec<_>>();
let sugg = find_best_match_for_name(
- symbols.iter(),
+ &symbols,
Symbol::intern(&format!("clippy::{}", name_lower)),
None,
);
/// }
/// ```
pub AWAIT_HOLDING_LOCK,
- correctness,
+ pedantic,
"Inside an async function, holding a MutexGuard while calling await"
}
/// use std::cell::RefCell;
///
/// async fn foo(x: &RefCell<u32>) {
- /// let b = x.borrow_mut()();
- /// *ref += 1;
+ /// let mut y = x.borrow_mut();
+ /// *y += 1;
/// bar.await;
/// }
/// ```
///
/// async fn foo(x: &RefCell<u32>) {
/// {
- /// let b = x.borrow_mut();
- /// *ref += 1;
+ /// let mut y = x.borrow_mut();
+ /// *y += 1;
/// }
/// bar.await;
/// }
/// ```
pub AWAIT_HOLDING_REFCELL_REF,
- correctness,
+ pedantic,
"Inside an async function, holding a RefCell ref while calling await"
}
/// [package]
/// name = "clippy"
/// version = "0.0.212"
+ /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
+ /// repository = "https://github.com/rust-lang/rust-clippy"
+ /// readme = "README.md"
+ /// license = "MIT OR Apache-2.0"
+ /// keywords = ["clippy", "lint", "plugin"]
+ /// categories = ["development-tools", "development-tools::cargo-plugins"]
+ /// ```
+ ///
+ /// Should include an authors field like:
+ ///
+ /// ```toml
+ /// # This `Cargo.toml` includes all common metadata
+ /// [package]
+ /// name = "clippy"
+ /// version = "0.0.212"
/// authors = ["Someone <someone@rust-lang.org>"]
/// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
/// repository = "https://github.com/rust-lang/rust-clippy"
pub TEMPORARY_CSTRING_AS_PTR,
"this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`"
}
+
+declare_deprecated_lint! {
+ pub PANIC_PARAMS,
+ "this lint has been uplifted to rustc and is now called `panic_fmt`"
+}
for &(p, _span) in preds {
let p = p.subst(cx.tcx, subst);
if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
- if Some(trait_ref.def_id()) == cx.tcx.lang_items().future_trait() {
+ if Some(trait_ref.value.def_id()) == cx.tcx.lang_items().future_trait() {
is_future = true;
break;
}
}
declare_clippy_lint! {
- /// **What it does:** Checks for comparing to an empty slice such as "" or [],`
+ /// **What it does:** Checks for comparing to an empty slice such as `""` or `[]`,
/// and suggests using `.is_empty()` where applicable.
///
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
+use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
declare_clippy_lint! {
/// **What it does:** Checks for `let _ = <expr>`
"non-binding let on a synchronization lock"
}
-declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]);
+declare_clippy_lint! {
+ /// **What it does:** Checks for `let _ = <expr>`
+ /// where expr has a type that implements `Drop`
+ ///
+ /// **Why is this bad?** This statement immediately drops the initializer
+ /// expression instead of extending its lifetime to the end of the scope, which
+ /// is often not intended. To extend the expression's lifetime to the end of the
+ /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
+ /// explicitly drop the expression, `std::mem::drop` conveys your intention
+ /// better and is less error-prone.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ ///
+ /// Bad:
+ /// ```rust,ignore
+ /// struct Droppable;
+ /// impl Drop for Droppable {
+ /// fn drop(&mut self) {}
+ /// }
+ /// {
+ /// let _ = Droppable;
+ /// // ^ dropped here
+ /// /* more code */
+ /// }
+ /// ```
+ ///
+ /// Good:
+ /// ```rust,ignore
+ /// {
+ /// let _droppable = Droppable;
+ /// /* more code */
+ /// // dropped at end of scope
+ /// }
+ /// ```
+ pub LET_UNDERSCORE_DROP,
+ pedantic,
+ "non-binding let on a type that implements `Drop`"
+}
+
+declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
&paths::MUTEX_GUARD,
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
});
+ let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait|
+ init_ty.walk().any(|inner| match inner.unpack() {
+ GenericArgKind::Type(inner_ty) => {
+ implements_trait(cx, inner_ty, drop_trait, &[])
+ },
+
+ GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
+ })
+ );
if contains_sync_guard {
span_lint_and_help(
cx,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
)
+ } else if implements_drop {
+ span_lint_and_help(
+ cx,
+ LET_UNDERSCORE_DROP,
+ local.span,
+ "non-binding `let` on a type that implements `Drop`",
+ None,
+ "consider using an underscore-prefixed named \
+ binding or dropping explicitly with `std::mem::drop`"
+ )
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
cx,
mod unit_return_expecting_ord;
mod unnamed_address;
mod unnecessary_sort_by;
+mod unnecessary_wraps;
mod unnested_or_patterns;
mod unsafe_removed_from_name;
mod unused_io_amount;
"clippy::temporary_cstring_as_ptr",
"this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`",
);
+ store.register_removed(
+ "clippy::panic_params",
+ "this lint has been uplifted to rustc and is now called `panic_fmt`",
+ );
// end deprecated lints, do not remove this comment, it’s used in `update_lints`
// begin register lints, do not remove this comment, it’s used in `update_lints`
&len_zero::LEN_WITHOUT_IS_EMPTY,
&len_zero::LEN_ZERO,
&let_if_seq::USELESS_LET_IF_SEQ,
+ &let_underscore::LET_UNDERSCORE_DROP,
&let_underscore::LET_UNDERSCORE_LOCK,
&let_underscore::LET_UNDERSCORE_MUST_USE,
&lifetimes::EXTRA_UNUSED_LIFETIMES,
&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
&panic_in_result_fn::PANIC_IN_RESULT_FN,
&panic_unimplemented::PANIC,
- &panic_unimplemented::PANIC_PARAMS,
&panic_unimplemented::TODO,
&panic_unimplemented::UNIMPLEMENTED,
&panic_unimplemented::UNREACHABLE,
&stable_sort_primitive::STABLE_SORT_PRIMITIVE,
&strings::STRING_ADD,
&strings::STRING_ADD_ASSIGN,
+ &strings::STRING_FROM_UTF8_AS_BYTES,
&strings::STRING_LIT_AS_BYTES,
&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
&unnamed_address::FN_ADDRESS_COMPARISONS,
&unnamed_address::VTABLE_ADDRESS_COMPARISONS,
&unnecessary_sort_by::UNNECESSARY_SORT_BY,
+ &unnecessary_wraps::UNNECESSARY_WRAPS,
&unnested_or_patterns::UNNESTED_OR_PATTERNS,
&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
&unused_io_amount::UNUSED_IO_AMOUNT,
store.register_late_pass(|| box redundant_clone::RedundantClone);
store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
+ store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
store.register_late_pass(|| box types::RefToMut);
store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn);
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(&attrs::INLINE_ALWAYS),
+ LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
+ LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
LintId::of(&bit_mask::VERBOSE_BIT_MASK),
LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
+ LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
LintId::of(&literal_representation::UNREADABLE_LITERAL),
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(&attrs::MISMATCHED_TARGET_OS),
LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
LintId::of(&attrs::USELESS_ATTRIBUTE),
- LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
- LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
LintId::of(&bit_mask::BAD_BIT_MASK),
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
LintId::of(&blacklisted_name::BLACKLISTED_NAME),
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
- LintId::of(&panic_unimplemented::PANIC_PARAMS),
LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(&precedence::PRECEDENCE),
LintId::of(&ptr::CMP_NULL),
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
+ LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES),
LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
LintId::of(&swap::ALMOST_SWAPPED),
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
+ LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
LintId::of(&unused_unit::UNUSED_UNIT),
LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
- LintId::of(&panic_unimplemented::PANIC_PARAMS),
LintId::of(&ptr::CMP_NULL),
LintId::of(&ptr::PTR_ARG),
LintId::of(&ptr_eq::PTR_EQ),
LintId::of(&reference::DEREF_ADDROF),
LintId::of(&reference::REF_IN_DEREF),
LintId::of(&repeat_once::REPEAT_ONCE),
+ LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES),
LintId::of(&swap::MANUAL_SWAP),
LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
LintId::of(&types::UNNECESSARY_CAST),
LintId::of(&types::VEC_BOX),
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
+ LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
LintId::of(&useless_conversion::USELESS_CONVERSION),
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
LintId::of(&attrs::DEPRECATED_SEMVER),
LintId::of(&attrs::MISMATCHED_TARGET_OS),
LintId::of(&attrs::USELESS_ATTRIBUTE),
- LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
- LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
LintId::of(&bit_mask::BAD_BIT_MASK),
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
LintId::of(&booleans::LOGIC_BUG),
use crate::utils::usage::{is_unused, mutated_variables};
use crate::utils::{
contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
- indent_of, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment,
- match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet,
- snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
- span_lint_and_then, sugg, SpanlessEq,
+ indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item,
+ last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path,
+ snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help,
+ span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq,
};
use if_chain::if_chain;
use rustc_ast::ast;
// (also matches an explicit "match" instead of "if let")
// (even if the "match" or "if let" is used for declaration)
if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind {
- // also check for empty `loop {}` statements
- // TODO(issue #6161): Enable for no_std crates (outside of #[panic_handler])
- if block.stmts.is_empty() && block.expr.is_none() && !is_no_std_crate(cx.tcx.hir().krate()) {
- span_lint_and_help(
- cx,
- EMPTY_LOOP,
- expr.span,
- "empty `loop {}` wastes CPU cycles",
- None,
- "You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.",
- );
+ // also check for empty `loop {}` statements, skipping those in #[panic_handler]
+ if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
+ let msg = "empty `loop {}` wastes CPU cycles";
+ let help = if is_no_std_crate(cx.tcx.hir().krate()) {
+ "you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body"
+ } else {
+ "you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body"
+ };
+ span_lint_and_help(cx, EMPTY_LOOP, expr.span, msg, None, help);
}
// extract the expression from the first statement (if any) in a block
use crate::utils::paths::FUTURE_FROM_GENERATOR;
-use crate::utils::{match_function_call, snippet_block, snippet_opt, span_lint_and_then};
+use crate::utils::{match_function_call, position_before_rarrow, snippet_block, snippet_opt, span_lint_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
|diag| {
if_chain! {
if let Some(header_snip) = snippet_opt(cx, header_span);
- if let Some(ret_pos) = header_snip.rfind("->");
+ if let Some(ret_pos) = position_before_rarrow(header_snip.clone());
if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
then {
let help = format!("make the function `async` and {}", ret_sugg);
},
_ => {
let sugg = "return the output of the future directly";
- snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip)))
+ snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip)))
},
}
}
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::Mutability;
use rustc_middle::ty;
+use rustc_middle::ty::adjustment::Adjust;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span};
declare_clippy_lint! {
- /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
- /// `iterator.cloned()` instead
+ /// **What it does:** Checks for usage of `map(|x| x.clone())` or
+ /// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
+ /// and suggests `cloned()` or `copied()` instead
///
/// **Why is this bad?** Readability, this can be written more concisely
///
}
}
},
- hir::ExprKind::MethodCall(ref method, _, ref obj, _) => {
- if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone"
- && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
-
- let obj_ty = cx.typeck_results().expr_ty(&obj[0]);
- if let ty::Ref(_, ty, _) = obj_ty.kind() {
- let copy = is_copy(cx, ty);
- lint(cx, e.span, args[0].span, copy);
+ hir::ExprKind::MethodCall(ref method, _, [obj], _) => if_chain! {
+ if ident_eq(name, obj) && method.ident.name == sym::clone;
+ if match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT);
+ // no autoderefs
+ if !cx.typeck_results().expr_adjustments(obj).iter()
+ .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
+ then {
+ let obj_ty = cx.typeck_results().expr_ty(obj);
+ if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
+ if matches!(mutability, Mutability::Not) {
+ let copy = is_copy(cx, ty);
+ lint(cx, e.span, args[0].span, copy);
+ }
} else {
lint_needless_cloning(cx, e.span, args[0].span);
}
use super::{contains_return, BIND_INSTEAD_OF_MAP};
use crate::utils::{
in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet,
- snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then,
+ snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
use rustc_span::Span;
pub(crate) struct OptionAndThenSome;
}
}
}
-
-/// returns `true` if expr contains match expr desugared from try
-fn contains_try(expr: &hir::Expr<'_>) -> bool {
- struct TryFinder {
- found: bool,
- }
-
- impl<'hir> intravisit::Visitor<'hir> for TryFinder {
- type Map = Map<'hir>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
- }
-
- fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
- if self.found {
- return;
- }
- match expr.kind {
- hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true,
- _ => intravisit::walk_expr(self, expr),
- }
- }
- }
-
- let mut visitor = TryFinder { found: false };
- visitor.visit_expr(expr);
- visitor.found
-}
-
-fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
-where
- F: FnMut(&'hir hir::Expr<'hir>) -> bool,
-{
- struct RetFinder<F> {
- in_stmt: bool,
- failed: bool,
- cb: F,
- }
-
- struct WithStmtGuarg<'a, F> {
- val: &'a mut RetFinder<F>,
- prev_in_stmt: bool,
- }
-
- impl<F> RetFinder<F> {
- fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
- let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
- WithStmtGuarg {
- val: self,
- prev_in_stmt,
- }
- }
- }
-
- impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
- type Target = RetFinder<F>;
-
- fn deref(&self) -> &Self::Target {
- self.val
- }
- }
-
- impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.val
- }
- }
-
- impl<F> Drop for WithStmtGuarg<'_, F> {
- fn drop(&mut self) {
- self.val.in_stmt = self.prev_in_stmt;
- }
- }
-
- impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
- type Map = Map<'hir>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
- }
-
- fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
- intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
- }
-
- fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
- if self.failed {
- return;
- }
- if self.in_stmt {
- match expr.kind {
- hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
- _ => intravisit::walk_expr(self, expr),
- }
- } else {
- match expr.kind {
- hir::ExprKind::Match(cond, arms, _) => {
- self.inside_stmt(true).visit_expr(cond);
- for arm in arms {
- self.visit_expr(arm.body);
- }
- },
- hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr),
- hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
- _ => self.failed |= !(self.cb)(expr),
- }
- }
- }
- }
-
- !contains_try(expr) && {
- let mut ret_finder = RetFinder {
- in_stmt: false,
- failed: false,
- cb: callback,
- };
- ret_finder.visit_expr(expr);
- !ret_finder.failed
- }
-}
}
declare_clippy_lint! {
- /// **What it does:** Checks for an iterator search (such as `find()`,
+ /// **What it does:** Checks for an iterator or string search (such as `find()`,
/// `position()`, or `rposition()`) followed by a call to `is_some()`.
///
/// **Why is this bad?** Readability, this can be written more concisely as
- /// `_.any(_)`.
+ /// `_.any(_)` or `_.contains(_)`.
///
/// **Known problems:** None.
///
/// ```
pub SEARCH_IS_SOME,
complexity,
- "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
+ "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`"
}
declare_clippy_lint! {
}
declare_clippy_lint! {
- /// **What it does:** Checks for usage of `_.map(_).collect::<Result<(),_>()`.
+ /// **What it does:** Checks for usage of `_.map(_).collect::<Result<(), _>()`.
///
/// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic.
///
cx: &LateContext<'tcx>,
name: &str,
method_span: Span,
- fun_span: Span,
self_expr: &hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>,
- or_has_args: bool,
span: Span,
+ // None if lambda is required
+ fun_span: Option<Span>,
) {
+ // (path, fn_has_argument, methods, suffix)
+ static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
+ (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
+ (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
+ (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
+ (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
+ ];
+
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
if path.ident.as_str() == "len" {
let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
}
}
- // (path, fn_has_argument, methods, suffix)
- let know_types: &[(&[_], _, &[_], _)] = &[
- (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
- (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
- (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
- (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
- ];
-
if_chain! {
- if know_types.iter().any(|k| k.2.contains(&name));
+ if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
if is_lazyness_candidate(cx, arg);
if !contains_return(&arg);
let self_ty = cx.typeck_results().expr_ty(self_expr);
if let Some(&(_, fn_has_arguments, poss, suffix)) =
- know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
+ KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0));
if poss.contains(&name);
then {
- let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
- (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
- (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
- (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."),
+ let sugg: Cow<'_, str> = {
+ let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
+ (false, Some(fun_span)) => (fun_span, false),
+ _ => (arg.span, true),
+ };
+ let snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
+ if use_lambda {
+ let l_arg = if fn_has_arguments { "_" } else { "" };
+ format!("|{}| {}", l_arg, snippet).into()
+ } else {
+ snippet
+ }
};
let span_replace_word = method_span.with_hi(span.hi());
span_lint_and_sugg(
hir::ExprKind::Call(ref fun, ref or_args) => {
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
- check_general_case(
- cx,
- name,
- method_span,
- fun.span,
- &args[0],
- &args[1],
- or_has_args,
- expr.span,
- );
+ let fun_span = if or_has_args { None } else { Some(fun.span) };
+ check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span);
}
},
- hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case(
- cx,
- name,
- method_span,
- span,
- &args[0],
- &args[1],
- !or_args.is_empty(),
- expr.span,
- ),
+ hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
+ check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
+ },
_ => {},
}
}
}
/// lint searching an Iterator followed by `is_some()`
+/// or calling `find()` on a string followed by `is_some()`
fn lint_search_is_some<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
// lint if caller of search is an Iterator
if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
let msg = format!(
- "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
- expressed by calling `any()`.",
+ "called `is_some()` after searching an `Iterator` with `{}`",
search_method
);
+ let hint = "this is more succinctly expressed by calling `any()`";
let search_snippet = snippet(cx, search_args[1].span, "..");
if search_snippet.lines().count() <= 1 {
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
SEARCH_IS_SOME,
method_span.with_hi(expr.span.hi()),
&msg,
- "try this",
+ "use `any()` instead",
format!(
"any({})",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
Applicability::MachineApplicable,
);
} else {
- span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
+ span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint);
+ }
+ }
+ // lint if `find()` is called by `String` or `&str`
+ else if search_method == "find" {
+ let is_string_or_str_slice = |e| {
+ let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
+ if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
+ true
+ } else {
+ *self_ty.kind() == ty::Str
+ }
+ };
+ if_chain! {
+ if is_string_or_str_slice(&search_args[0]);
+ if is_string_or_str_slice(&search_args[1]);
+ then {
+ let msg = "called `is_some()` after calling `find()` on a string";
+ let mut applicability = Applicability::MachineApplicable;
+ let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ SEARCH_IS_SOME,
+ method_span.with_hi(expr.span.hi()),
+ msg,
+ "use `contains()` instead",
+ format!("contains({})", find_arg),
+ applicability,
+ );
+ }
}
}
}
let ty = cx.typeck_results().expr_ty(expr);
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
- let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap();
- let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap();
+ if_chain! {
+ if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR);
+ if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR);
- if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) {
- // `expr` implements `FromIterator` trait
- let iter_expr = snippet(cx, args[0].span, "..");
- span_lint_and_sugg(
- cx,
- FROM_ITER_INSTEAD_OF_COLLECT,
- expr.span,
- "usage of `FromIterator::from_iter`",
- "use `.collect()` instead of `::from_iter()`",
- format!("{}.collect()", iter_expr),
- Applicability::MaybeIncorrect,
- );
+ if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]);
+ then {
+ // `expr` implements `FromIterator` trait
+ let iter_expr = snippet(cx, args[0].span, "..");
+ span_lint_and_sugg(
+ cx,
+ FROM_ITER_INSTEAD_OF_COLLECT,
+ expr.span,
+ "usage of `FromIterator::from_iter`",
+ "use `.collect()` instead of `::from_iter()`",
+ format!("{}.collect()", iter_expr),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
} else {
"unnecessary closure used to substitute value for `Result::Err`"
};
+ let applicability = if body
+ .params
+ .iter()
+ // bindings are checked to be unused above
+ .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild))
+ {
+ Applicability::MachineApplicable
+ } else {
+ // replacing the lambda may break type inference
+ Applicability::MaybeIncorrect
+ };
span_lint_and_sugg(
cx,
simplify_using,
snippet(cx, body_expr.span, ".."),
),
- Applicability::MachineApplicable,
+ applicability,
);
}
}
hir::ItemKind::Union(..) => "a union",
hir::ItemKind::OpaqueTy(..) => "an existential type",
hir::ItemKind::ExternCrate(..)
- | hir::ItemKind::ForeignMod(..)
+ | hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::Impl { .. }
| hir::ItemKind::Use(..) => return,
| hir::ItemKind::Union(..)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::ExternCrate(..)
- | hir::ItemKind::ForeignMod(..)
+ | hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Impl { .. }
| hir::ItemKind::Use(..) => {},
};
for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) {
check_ty(cx, hir_ty.span, ty);
}
- check_ty(
- cx,
- decl.output.span(),
- cx.tcx.erase_late_bound_regions(fn_sig.output()),
- );
+ check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
}
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
use std::ptr;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{
+ BodyId, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
+};
use rustc_infer::traits::specialization_graph;
use rustc_lint::{LateContext, LateLintPass, Lint};
+use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{AssocKind, Ty};
+use rustc_middle::ty::{self, AssocKind, Const, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{InnerSpan, Span, DUMMY_SP};
use rustc_typeck::hir_ty_to_ty;
/// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
/// and this lint should be suppressed.
///
- /// When an enum has variants with interior mutability, use of its non interior mutable
- /// variants can generate false positives. See issue
- /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+ /// Even though the lint avoids triggering on a constant whose type has enums that have variants
+ /// with interior mutability, and its value uses non interior mutable variants (see
+ /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
+ /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
+ /// it complains about associated constants without default values only based on its types;
+ /// which might not be preferable.
+ /// There're other enums plus associated constants cases that the lint cannot handle.
///
/// Types that have underlying or potential interior mutability trigger the lint whether
/// the interior mutable field is used or not. See issues
/// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
- /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
///
/// **Example:**
/// ```rust
"referencing `const` with interior mutability"
}
+fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+ // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
+ // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
+ // 'unfrozen'. However, this code causes a false negative in which
+ // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell<T>`.
+ // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
+ // since it works when a pointer indirection involves (`Cell<*const T>`).
+ // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
+ // but I'm not sure whether it's a decent way, if possible.
+ cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+}
+
+fn is_value_unfrozen_raw<'tcx>(
+ cx: &LateContext<'tcx>,
+ result: Result<ConstValue<'tcx>, ErrorHandled>,
+ ty: Ty<'tcx>,
+) -> bool {
+ fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool {
+ match val.ty.kind() {
+ // the fact that we have to dig into every structs to search enums
+ // leads us to the point checking `UnsafeCell` directly is the only option.
+ ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true,
+ ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
+ let val = cx.tcx.destructure_const(cx.param_env.and(val));
+ val.fields.iter().any(|field| inner(cx, field))
+ },
+ _ => false,
+ }
+ }
+
+ result.map_or_else(
+ |err| {
+ // Consider `TooGeneric` cases as being unfrozen.
+ // This causes a false positive where an assoc const whose type is unfrozen
+ // have a value that is a frozen variant with a generic param (an example is
+ // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
+ // However, it prevents a number of false negatives that is, I think, important:
+ // 1. assoc consts in trait defs referring to consts of themselves
+ // (an example is `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
+ // 2. a path expr referring to assoc consts whose type is doesn't have
+ // any frozen variants in trait defs (i.e. without substitute for `Self`).
+ // (e.g. borrowing `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
+ // 3. similar to the false positive above;
+ // but the value is an unfrozen variant, or the type has no enums. (An example is
+ // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT`
+ // and `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
+ // One might be able to prevent these FNs correctly, and replace this with `false`;
+ // e.g. implementing `has_frozen_variant` described above, and not running this function
+ // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
+ // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
+ // similar to 2., but with the a frozen variant) (e.g. borrowing
+ // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
+ // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
+ err == ErrorHandled::TooGeneric
+ },
+ |val| inner(cx, Const::from_value(cx.tcx, val, ty)),
+ )
+}
+
+fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
+ let result = cx.tcx.const_eval_poly(body_id.hir_id.owner.to_def_id());
+ is_value_unfrozen_raw(cx, result, ty)
+}
+
+fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
+ let substs = cx.typeck_results().node_substs(hir_id);
+
+ let result = cx
+ .tcx
+ .const_eval_resolve(cx.param_env, ty::WithOptConstParam::unknown(def_id), substs, None, None);
+ is_value_unfrozen_raw(cx, result, ty)
+}
+
#[derive(Copy, Clone)]
enum Source {
Item { item: Span },
}
}
-fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
- // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
- // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
- // 'unfrozen'. However, this code causes a false negative in which
- // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell<T>`.
- // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
- // since it works when a pointer indirection involves (`Cell<*const T>`).
- // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
- // but I'm not sure whether it's a decent way, if possible.
- if cx.tcx.layout_of(cx.param_env.and(ty)).is_err() || ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) {
- return;
- }
-
+fn lint(cx: &LateContext<'_>, source: Source) {
let (lint, msg, span) = source.lint();
span_lint_and_then(cx, lint, span, msg, |diag| {
if span.from_expansion() {
impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
- if let ItemKind::Const(hir_ty, ..) = &it.kind {
+ if let ItemKind::Const(hir_ty, body_id) = it.kind {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
- verify_ty_bound(cx, ty, Source::Item { item: it.span });
+
+ if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) {
+ lint(cx, Source::Item { item: it.span });
+ }
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
- if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
+ if let TraitItemKind::Const(hir_ty, body_id_opt) = &trait_item.kind {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+
// Normalize assoc types because ones originated from generic params
// bounded other traits could have their bound.
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
- verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span });
+ if is_unfrozen(cx, normalized)
+ // When there's no default value, lint it only according to its type;
+ // in other words, lint consts whose value *could* be unfrozen, not definitely is.
+ // This feels inconsistent with how the lint treats generic types,
+ // which avoids linting types which potentially become unfrozen.
+ // One could check whether a unfrozen type have a *frozen variant*
+ // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`),
+ // and do the same as the case of generic types at impl items.
+ // Note that it isn't sufficient to check if it has an enum
+ // since all of that enum's variants can be unfrozen:
+ // i.e. having an enum doesn't necessary mean a type has a frozen variant.
+ // And, implementing it isn't a trivial task; it'll probably end up
+ // re-implementing the trait predicate evaluation specific to `Freeze`.
+ && body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized))
+ {
+ lint(cx, Source::Assoc { item: trait_item.span });
+ }
}
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
- if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind {
+ if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
let item = cx.tcx.hir().expect_item(item_hir_id);
),
))
.is_err();
+ // If there were a function like `has_frozen_variant` described above,
+ // we should use here as a frozen variant is a potential to be frozen
+ // similar to unknown layouts.
+ // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
then {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
- verify_ty_bound(
- cx,
- normalized,
- Source::Assoc {
- item: impl_item.span,
- },
- );
+ if is_unfrozen(cx, normalized)
+ && is_value_unfrozen_poly(cx, *body_id, normalized)
+ {
+ lint(
+ cx,
+ Source::Assoc {
+ item: impl_item.span,
+ },
+ );
+ }
}
}
},
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
// Normalize assoc types originated from generic params.
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
- verify_ty_bound(cx, normalized, Source::Assoc { item: impl_item.span });
+
+ if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) {
+ lint(cx, Source::Assoc { item: impl_item.span });
+ }
},
_ => (),
}
}
// Make sure it is a const item.
- match qpath_res(cx, qpath, expr.hir_id) {
- Res::Def(DefKind::Const | DefKind::AssocConst, _) => {},
+ let item_def_id = match qpath_res(cx, qpath, expr.hir_id) {
+ Res::Def(DefKind::Const | DefKind::AssocConst, did) => did,
_ => return,
};
cx.typeck_results().expr_ty(dereferenced_expr)
};
- verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
+ if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) {
+ lint(cx, Source::Expr { expr: expr.span });
+ }
}
}
}
use crate::utils::{span_lint, span_lint_and_then};
-use rustc_ast::ast::{
- Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
-};
+use rustc_ast::ast::{Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind};
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_middle::lint::in_external_macro;
-use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, span_lint};
+use crate::utils::{is_expn_of, match_panic_call, span_lint};
use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
-declare_clippy_lint! {
- /// **What it does:** Checks for missing parameters in `panic!`.
- ///
- /// **Why is this bad?** Contrary to the `format!` family of macros, there are
- /// two forms of `panic!`: if there are no parameters given, the first argument
- /// is not a format string and used literally. So while `format!("{}")` will
- /// fail to compile, `panic!("{}")` will not.
- ///
- /// **Known problems:** None.
- ///
- /// **Example:**
- /// ```no_run
- /// panic!("This `panic!` is probably missing a parameter there: {}");
- /// ```
- pub PANIC_PARAMS,
- style,
- "missing parameters in `panic!` calls"
-}
-
declare_clippy_lint! {
/// **What it does:** Checks for usage of `panic!`.
///
"`unreachable!` should not be present in production code"
}
-declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
+declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let Some(params) = match_panic_call(cx, expr) {
+ if match_panic_call(cx, expr).is_some() {
let span = get_outer_span(expr);
if is_expn_of(expr.span, "unimplemented").is_some() {
span_lint(
);
} else if is_expn_of(expr.span, "panic").is_some() {
span_lint(cx, PANIC, span, "`panic` should not be present in production code");
- match_panic(params, expr, cx);
}
}
}
}
}
}
-
-fn match_panic(params: &[Expr<'_>], expr: &Expr<'_>, cx: &LateContext<'_>) {
- if_chain! {
- if let ExprKind::Lit(ref lit) = params[0].kind;
- if is_direct_expn_of(expr.span, "panic").is_some();
- if let LitKind::Str(ref string, _) = lit.node;
- let string = string.as_str().replace("{{", "").replace("}}", "");
- if let Some(par) = string.find('{');
- if string[par..].contains('}');
- if params[0].span.source_callee().is_none();
- if params[0].span.lo() != params[0].span.hi();
- then {
- span_lint(cx, PANIC_PARAMS, params[0].span,
- "you probably are missing some parameter in your format string");
- }
- }
-}
let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
+ let space = if lo.ends_with('.') { " " } else { "" };
span_lint_and_sugg(
cx,
MANUAL_RANGE_CONTAINS,
span,
&format!("manual `{}::contains` implementation", range_type),
"use",
- format!("({}{}{}).contains(&{})", lo, range_op, hi, name),
+ format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
applicability,
);
} else if !combine_and && ord == Some(lord) {
let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
+ let space = if lo.ends_with('.') { " " } else { "" };
span_lint_and_sugg(
cx,
MANUAL_RANGE_CONTAINS,
span,
&format!("manual `!{}::contains` implementation", range_type),
"use",
- format!("!({}{}{}).contains(&{})", lo, range_op, hi, name),
+ format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
applicability,
);
}
match (by_ref, &*rvalue) {
(true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => {
- base_local_and_movability(cx, mir, *place)
+ Some(base_local_and_movability(cx, mir, *place))
},
(false, mir::Rvalue::Ref(_, _, place)) => {
if let [mir::ProjectionElem::Deref] = place.as_ref().projection {
- base_local_and_movability(cx, mir, *place)
+ Some(base_local_and_movability(cx, mir, *place))
} else {
None
}
cx: &LateContext<'tcx>,
mir: &mir::Body<'tcx>,
place: mir::Place<'tcx>,
-) -> Option<(mir::Local, CannotMoveOut)> {
+) -> (mir::Local, CannotMoveOut) {
use rustc_middle::mir::PlaceRef;
// Dereference. You cannot move things out from a borrowed value.
&& !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
}
- Some((local, deref || field || slice))
+ (local, deref || field || slice)
}
struct LocalUseVisitor {
-use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
+use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
-use rustc_ast::ast::{Expr, ExprKind, UnOp};
+use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::BytePos;
declare_clippy_lint! {
/// **What it does:** Checks for usage of `*&` and `*&mut` in expressions.
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
if_chain! {
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
- if let ExprKind::AddrOf(_, _, ref addrof_target) = without_parens(deref_target).kind;
+ if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
if !in_macro(addrof_target.span);
then {
let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- DEREF_ADDROF,
- e.span,
- "immediately dereferencing a reference",
- "try this",
- format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)),
- applicability,
- );
+ let sugg = if e.span.from_expansion() {
+ if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) {
+ // Remove leading whitespace from the given span
+ // e.g: ` $visitor` turns into `$visitor`
+ let trim_leading_whitespaces = |span| {
+ snippet_opt(cx, span).and_then(|snip| {
+ #[allow(clippy::cast_possible_truncation)]
+ snip.find(|c: char| !c.is_whitespace()).map(|pos| {
+ span.lo() + BytePos(pos as u32)
+ })
+ }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace))
+ };
+
+ let mut generate_snippet = |pattern: &str| {
+ #[allow(clippy::cast_possible_truncation)]
+ macro_source.rfind(pattern).map(|pattern_pos| {
+ let rpos = pattern_pos + pattern.len();
+ let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
+ let span = trim_leading_whitespaces(span_after_ref);
+ snippet_with_applicability(cx, span, "_", &mut applicability)
+ })
+ };
+
+ if *mutability == Mutability::Mut {
+ generate_snippet("mut")
+ } else {
+ generate_snippet("&")
+ }
+ } else {
+ Some(snippet_with_applicability(cx, e.span, "_", &mut applicability))
+ }
+ } else {
+ Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability))
+ };
+ if let Some(sugg) = sugg {
+ span_lint_and_sugg(
+ cx,
+ DEREF_ADDROF,
+ e.span,
+ "immediately dereferencing a reference",
+ "try this",
+ sugg.to_string(),
+ applicability,
+ );
+ }
}
}
}
declare_clippy_lint! {
/// **What it does:** Checks [regex](https://crates.io/crates/regex) creation
- /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct
+ /// (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct
/// regex syntax.
///
/// **Why is this bad?** This will lead to a runtime panic.
declare_clippy_lint! {
/// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex)
- /// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`).
+ /// creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`).
///
/// **Why is this bad?** Matching the regex can likely be replaced by `==` or
/// `str::starts_with`, `str::ends_with` or `std::contains` or other `str`
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use if_chain::if_chain;
use crate::utils::SpanlessEq;
-use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};
+use crate::utils::{
+ get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint,
+ span_lint_and_sugg,
+};
declare_clippy_lint! {
/// **What it does:** Checks for string appends of the form `x = x + y` (without
}
}
+declare_clippy_lint! {
+ /// **What it does:** Check if the string is transformed to byte array and casted back to string.
+ ///
+ /// **Why is this bad?** It's unnecessary, the string can be used directly.
+ ///
+ /// **Known problems:** None
+ ///
+ /// **Example:**
+ /// ```rust
+ /// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
+ /// ```
+ /// could be written as
+ /// ```rust
+ /// let _ = &"Hello World!"[6..11];
+ /// ```
+ pub STRING_FROM_UTF8_AS_BYTES,
+ complexity,
+ "casting string slices to byte slices and back"
+}
+
// Max length a b"foo" string can take
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;
-declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);
+declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
use crate::utils::{snippet, snippet_with_applicability};
use rustc_ast::LitKind;
+ if_chain! {
+ // Find std::str::converts::from_utf8
+ if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8);
+
+ // Find string::as_bytes
+ if let ExprKind::AddrOf(BorrowKind::Ref, _, ref args) = args[0].kind;
+ if let ExprKind::Index(ref left, ref right) = args.kind;
+ let (method_names, expressions, _) = method_calls(left, 1);
+ if method_names.len() == 1;
+ if expressions.len() == 1;
+ if expressions[0].len() == 1;
+ if method_names[0] == sym!(as_bytes);
+
+ // Check for slicer
+ if let ExprKind::Struct(ref path, _, _) = right.kind;
+ if let QPath::LangItem(LangItem::Range, _) = path;
+
+ then {
+ let mut applicability = Applicability::MachineApplicable;
+ let string_expression = &expressions[0][0];
+
+ let snippet_app = snippet_with_applicability(
+ cx,
+ string_expression.span, "..",
+ &mut applicability,
+ );
+
+ span_lint_and_sugg(
+ cx,
+ STRING_FROM_UTF8_AS_BYTES,
+ e.span,
+ "calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
+ "try",
+ format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")),
+ applicability
+ )
+ }
+ }
+
if_chain! {
if let ExprKind::MethodCall(path, _, args, _) = &e.kind;
if path.ident.name == sym!(as_bytes);
use crate::utils::{
- is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
- span_lint_and_sugg,
+ differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet,
+ snippet_with_macro_callsite, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
};
let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
+ let differing_contexts = differing_macro_contexts(expr.span, err_arg.span);
- let origin_snippet = if err_arg.span.from_expansion() {
+ let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts {
+ snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_")
+ } else if err_arg.span.from_expansion() && !in_macro(expr.span) {
snippet_with_macro_callsite(cx, err_arg.span, "_")
} else {
snippet(cx, err_arg.span, "_")
hir_ty.span,
"`Vec<T>` is already on the heap, the boxing is unnecessary.",
"try",
- format!("Vec<{}>", ty_ty),
+ format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
Applicability::MachineApplicable,
);
return; // don't recurse into the type
/// **Example:**
///
/// ```rust
- /// let mut twins = vec!((1,1), (2,2));
+ /// let mut twins = vec!((1, 1), (2, 2));
/// twins.sort_by_key(|x| { x.1; });
/// ```
pub UNIT_RETURN_EXPECTING_ORD,
--- /dev/null
+use crate::utils::{
+ in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
+ visitors::find_all_ret_expressions,
+};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
+ ///
+ /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
+ ///
+ /// **Known problems:** Since this lint changes function type signature, you may need to
+ /// adjust some code at callee side.
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
+ /// if a && b {
+ /// return Some(50);
+ /// }
+ /// if a {
+ /// Some(0)
+ /// } else {
+ /// Some(10)
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn get_cool_number(a: bool, b: bool) -> i32 {
+ /// if a && b {
+ /// return 50;
+ /// }
+ /// if a {
+ /// 0
+ /// } else {
+ /// 10
+ /// }
+ /// }
+ /// ```
+ pub UNNECESSARY_WRAPS,
+ complexity,
+ "functions that only return `Ok` or `Some`"
+}
+
+declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+
+impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ fn_kind: FnKind<'tcx>,
+ fn_decl: &FnDecl<'tcx>,
+ body: &Body<'tcx>,
+ span: Span,
+ hir_id: HirId,
+ ) {
+ match fn_kind {
+ FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
+ if visibility.node.is_pub() {
+ return;
+ }
+ },
+ FnKind::Closure(..) => return,
+ _ => (),
+ }
+
+ if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+ if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) {
+ return;
+ }
+ }
+
+ let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
+ ("Option", &paths::OPTION_SOME)
+ } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
+ ("Result", &paths::RESULT_OK)
+ } else {
+ return;
+ };
+
+ let mut suggs = Vec::new();
+ let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
+ if_chain! {
+ if !in_macro(ret_expr.span);
+ if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
+ if let ExprKind::Path(ref qpath) = func.kind;
+ if match_qpath(qpath, path);
+ if args.len() == 1;
+ then {
+ suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
+ true
+ } else {
+ false
+ }
+ }
+ });
+
+ if can_sugg && !suggs.is_empty() {
+ span_lint_and_then(
+ cx,
+ UNNECESSARY_WRAPS,
+ span,
+ format!(
+ "this function's return value is unnecessarily wrapped by `{}`",
+ return_type
+ )
+ .as_str(),
+ |diag| {
+ let inner_ty = return_ty(cx, hir_id)
+ .walk()
+ .skip(1) // skip `std::option::Option` or `std::result::Result`
+ .take(1) // take the first outermost inner type
+ .filter_map(|inner| match inner.unpack() {
+ GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
+ _ => None,
+ });
+ inner_ty.for_each(|inner_ty| {
+ diag.span_suggestion(
+ fn_decl.output.span(),
+ format!("remove `{}` from the return type...", return_type).as_str(),
+ inner_ty,
+ Applicability::MaybeIncorrect,
+ );
+ });
+ diag.multipart_suggestion(
+ "...and change the returning expressions",
+ suggs,
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ }
+ }
+}
use rustc_span::source_map::Span;
use rustc_span::BytePos;
-use crate::utils::span_lint_and_sugg;
+use crate::utils::{position_before_rarrow, span_lint_and_sugg};
declare_clippy_lint! {
/// **What it does:** Checks for unit (`()`) expressions that can be removed.
fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
- fn_source
- .rfind("->")
- .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
- let mut rpos = rpos;
- let chars: Vec<char> = fn_source.chars().collect();
- while rpos > 1 {
- if let Some(c) = chars.get(rpos - 1) {
- if c.is_whitespace() {
- rpos -= 1;
- continue;
- }
- }
- break;
- }
- (
- #[allow(clippy::cast_possible_truncation)]
- ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
- Applicability::MachineApplicable,
- )
- })
+ position_before_rarrow(fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
+ (
+ #[allow(clippy::cast_possible_truncation)]
+ ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
+ Applicability::MachineApplicable,
+ )
+ })
} else {
(ty.span, Applicability::MaybeIncorrect)
};
use rustc_span::sym;
declare_clippy_lint! {
- /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls
- /// that useless converts to the same type as caller.
+ /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls
+ /// which uselessly convert to the same type.
///
/// **Why is this bad?** Redundant code.
///
/// ```
pub USELESS_CONVERSION,
complexity,
- "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type"
+ "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type"
}
#[derive(Default)]
pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
match (l, r) {
(StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb),
- (StructRest::Rest(_), StructRest::Rest(_)) => true,
- (StructRest::None, StructRest::None) => true,
+ (StructRest::Rest(_), StructRest::Rest(_)) | (StructRest::None, StructRest::None) => true,
_ => false,
}
}
//! - or-fun-call
//! - option-if-let-else
-use crate::utils::is_ctor_or_promotable_const_function;
+use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit;
let call_found = match &expr.kind {
// ignore enum and struct constructors
ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
+ ExprKind::Index(obj, _) => {
+ let ty = self.cx.typeck_results().expr_ty(obj);
+ is_type_diagnostic_item(self.cx, ty, sym!(hashmap_type))
+ || match_type(self.cx, ty, &paths::BTREEMAP)
+ },
ExprKind::MethodCall(..) => true,
_ => false,
};
println!("function of type {:#?}", item_ty);
},
hir::ItemKind::Mod(..) => println!("module"),
- hir::ItemKind::ForeignMod(ref fm) => println!("foreign module with abi: {}", fm.abi),
+ hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi),
hir::ItemKind::GlobalAsm(ref asm) => println!("global asm: {:?}", asm),
hir::ItemKind::TyAlias(..) => {
println!("type alias for {:?}", cx.tcx.type_of(did));
pub mod qualify_min_const_fn;
pub mod sugg;
pub mod usage;
+pub mod visitors;
pub use self::attrs::*;
pub use self::diagnostics::*;
return false;
}
let ty = cx.tcx.erase_regions(ty);
+ if ty.has_escaping_bound_vars() {
+ return false;
+ }
let ty_params = cx.tcx.mk_substs(ty_params.iter());
cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
}
.map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
}
+/// Returns `true` if the expression is in the program's `#[panic_handler]`.
+pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+ let parent = cx.tcx.hir().get_parent_item(e.hir_id);
+ let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
+ Some(def_id) == cx.tcx.lang_items().panic_impl()
+}
+
/// Gets the name of the item the expression is in, if available.
pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
}
+/// Returns the positon just before rarrow
+///
+/// ```rust,ignore
+/// fn into(self) -> () {}
+/// ^
+/// // in case of unformatted code
+/// fn into2(self)-> () {}
+/// ^
+/// fn into3(self) -> () {}
+/// ^
+/// ```
+#[allow(clippy::needless_pass_by_value)]
+pub fn position_before_rarrow(s: String) -> Option<usize> {
+ s.rfind("->").map(|rpos| {
+ let mut rpos = rpos;
+ let chars: Vec<char> = s.chars().collect();
+ while rpos > 1 {
+ if let Some(c) = chars.get(rpos - 1) {
+ if c.is_whitespace() {
+ rpos -= 1;
+ continue;
+ }
+ }
+ break;
+ }
+ rpos
+ })
+}
+
/// Extends the span to the beginning of the spans line, incl. whitespaces.
///
/// ```rust,ignore
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
+pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"];
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
--- /dev/null
+use rustc_hir as hir;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_lint::LateContext;
+use rustc_middle::hir::map::Map;
+
+/// returns `true` if expr contains match expr desugared from try
+fn contains_try(expr: &hir::Expr<'_>) -> bool {
+ struct TryFinder {
+ found: bool,
+ }
+
+ impl<'hir> intravisit::Visitor<'hir> for TryFinder {
+ type Map = Map<'hir>;
+
+ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+ intravisit::NestedVisitorMap::None
+ }
+
+ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
+ if self.found {
+ return;
+ }
+ match expr.kind {
+ hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true,
+ _ => intravisit::walk_expr(self, expr),
+ }
+ }
+ }
+
+ let mut visitor = TryFinder { found: false };
+ visitor.visit_expr(expr);
+ visitor.found
+}
+
+pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
+where
+ F: FnMut(&'hir hir::Expr<'hir>) -> bool,
+{
+ struct RetFinder<F> {
+ in_stmt: bool,
+ failed: bool,
+ cb: F,
+ }
+
+ struct WithStmtGuarg<'a, F> {
+ val: &'a mut RetFinder<F>,
+ prev_in_stmt: bool,
+ }
+
+ impl<F> RetFinder<F> {
+ fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
+ let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
+ WithStmtGuarg {
+ val: self,
+ prev_in_stmt,
+ }
+ }
+ }
+
+ impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
+ type Target = RetFinder<F>;
+
+ fn deref(&self) -> &Self::Target {
+ self.val
+ }
+ }
+
+ impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.val
+ }
+ }
+
+ impl<F> Drop for WithStmtGuarg<'_, F> {
+ fn drop(&mut self) {
+ self.val.in_stmt = self.prev_in_stmt;
+ }
+ }
+
+ impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
+ type Map = Map<'hir>;
+
+ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+ intravisit::NestedVisitorMap::None
+ }
+
+ fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
+ intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
+ }
+
+ fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
+ if self.failed {
+ return;
+ }
+ if self.in_stmt {
+ match expr.kind {
+ hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
+ _ => intravisit::walk_expr(self, expr),
+ }
+ } else {
+ match expr.kind {
+ hir::ExprKind::Match(cond, arms, _) => {
+ self.inside_stmt(true).visit_expr(cond);
+ for arm in arms {
+ self.visit_expr(arm.body);
+ }
+ },
+ hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr),
+ hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
+ _ => self.failed |= !(self.cb)(expr),
+ }
+ }
+ }
+ }
+
+ !contains_try(expr) && {
+ let mut ret_finder = RetFinder {
+ in_stmt: false,
+ failed: false,
+ cb: callback,
+ };
+ ret_finder.visit_expr(expr);
+ !ret_finder.failed
+ }
+}
* When writing the release notes for the **upcoming beta release**, you need to check
out the Clippy commit of the current Rust `master`. [Link][rust_master_tools]
* When writing the (forgotten) release notes for a **past stable release**, you
- need to select the Rust release tag from the dropdown and then check the
- commit of the Clippy directory:
+ need to check out the Rust release tag of the stable release.
+ [Link][rust_stable_tools]
+
+Usually you want to wirte the changelog of the **upcoming stable release**. Make
+sure though, that `beta` was already branched in the Rust repository.
To find the commit hash, issue the following command when in a `rust-lang/rust` checkout:
```
7. Documentation improvements
8. Others
+As section headers, we use:
+
+```
+### New Lints
+### Moves and Deprecations
+### Enhancements
+### False Positive Fixes
+### Suggestion Fixes/Improvements
+### ICE Fixes
+### Documentation Improvements
+### Others
+```
+
Please also be sure to update the Beta/Unreleased sections at the top with the
relevant commit ranges.
[forge]: https://forge.rust-lang.org/
[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy
[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy
+[rust_stable_tools]: https://github.com/rust-lang/rust/releases
// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
-extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_interface;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};
-mod lintlist;
-
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a, T: Deref<Target = str>>(
}
}
-#[allow(clippy::find_map, clippy::filter_map)]
-fn describe_lints() {
- use lintlist::{Level, Lint, ALL_LINTS, LINT_LEVELS};
- use rustc_data_structures::fx::FxHashSet;
-
- println!(
- "
-Available lint options:
- -W <foo> Warn about <foo>
- -A <foo> Allow <foo>
- -D <foo> Deny <foo>
- -F <foo> Forbid <foo> (deny <foo> and all attempts to override)
-
-"
- );
-
- let lint_level = |lint: &Lint| {
- LINT_LEVELS
- .iter()
- .find(|level_mapping| level_mapping.0 == lint.group)
- .map(|(_, level)| match level {
- Level::Allow => "allow",
- Level::Warn => "warn",
- Level::Deny => "deny",
- })
- .unwrap()
- };
-
- let mut lints: Vec<_> = ALL_LINTS.iter().collect();
- // The sort doesn't case-fold but it's doubtful we care.
- lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));
-
- let max_lint_name_len = lints
- .iter()
- .map(|lint| lint.name.len())
- .map(|len| len + "clippy::".len())
- .max()
- .unwrap_or(0);
-
- let padded = |x: &str| {
- let mut s = " ".repeat(max_lint_name_len - x.chars().count());
- s.push_str(x);
- s
- };
-
- let scoped = |x: &str| format!("clippy::{}", x);
-
- let lint_groups: FxHashSet<_> = lints.iter().map(|lint| lint.group).collect();
-
- println!("Lint checks provided by clippy:\n");
- println!(" {} {:7.7} meaning", padded("name"), "default");
- println!(" {} {:7.7} -------", padded("----"), "-------");
-
- let print_lints = |lints: &[&Lint]| {
- for lint in lints {
- let name = lint.name.replace("_", "-");
- println!(
- " {} {:7.7} {}",
- padded(&scoped(&name)),
- lint_level(lint),
- lint.desc
- );
- }
- println!("\n");
- };
-
- print_lints(&lints);
-
- let max_group_name_len = std::cmp::max(
- "clippy::all".len(),
- lint_groups
- .iter()
- .map(|group| group.len())
- .map(|len| len + "clippy::".len())
- .max()
- .unwrap_or(0),
- );
-
- let padded_group = |x: &str| {
- let mut s = " ".repeat(max_group_name_len - x.chars().count());
- s.push_str(x);
- s
- };
-
- println!("Lint groups provided by clippy:\n");
- println!(" {} sub-lints", padded_group("name"));
- println!(" {} ---------", padded_group("----"));
- println!(" {} the set of all clippy lints", padded_group("clippy::all"));
-
- let print_lint_groups = || {
- for group in lint_groups {
- let name = group.to_lowercase().replace("_", "-");
- let desc = lints
- .iter()
- .filter(|&lint| lint.group == group)
- .map(|lint| lint.name)
- .map(|name| name.replace("_", "-"))
- .collect::<Vec<String>>()
- .join(", ");
- println!(" {} {}", padded_group(&scoped(&name)), desc);
- }
- println!("\n");
- };
-
- print_lint_groups();
-}
-
fn display_help() {
println!(
"\
exit(0);
}
- let should_describe_lints = || {
- let args: Vec<_> = env::args().collect();
- args.windows(2)
- .any(|args| args[1] == "help" && matches!(args[0].as_str(), "-W" | "-A" | "-D" | "-F"))
- };
-
- if !wrapper_mode && should_describe_lints() {
- describe_lints();
- exit(0);
- }
-
// this conditional check for the --sysroot flag is there so users can call
// `clippy_driver` directly
// without having to pass --sysroot or anything
+++ /dev/null
-/// Lint data parsed from the Clippy source code.
-#[derive(Clone, PartialEq, Debug)]
-pub struct Lint {
- pub name: &'static str,
- pub group: &'static str,
- pub desc: &'static str,
- pub deprecation: Option<&'static str>,
- pub module: &'static str,
-}
-
-#[derive(PartialOrd, PartialEq, Ord, Eq)]
-pub enum Level {
- Allow,
- Warn,
- Deny,
-}
-
-pub const LINT_LEVELS: [(&str, Level); 8] = [
- ("correctness", Level::Deny),
- ("style", Level::Warn),
- ("complexity", Level::Warn),
- ("perf", Level::Warn),
- ("restriction", Level::Allow),
- ("pedantic", Level::Allow),
- ("nursery", Level::Allow),
- ("cargo", Level::Allow),
-];
+++ /dev/null
-//! This file is managed by `cargo dev update_lints`. Do not edit or format this file.
-
-use std::lazy::SyncLazy;
-
-pub mod lint;
-pub use lint::Level;
-pub use lint::Lint;
-pub use lint::LINT_LEVELS;
-
-#[rustfmt::skip]
-pub static ALL_LINTS: SyncLazy<Vec<Lint>> = SyncLazy::new(|| {
-// begin lint list, do not remove this comment, it’s used in `update_lints`
-vec![
- Lint {
- name: "absurd_extreme_comparisons",
- group: "correctness",
- desc: "a comparison with a maximum or minimum value that is always true or false",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "almost_swapped",
- group: "correctness",
- desc: "`foo = bar; bar = foo` sequence",
- deprecation: None,
- module: "swap",
- },
- Lint {
- name: "approx_constant",
- group: "correctness",
- desc: "the approximate of a known float constant (in `std::fXX::consts`)",
- deprecation: None,
- module: "approx_const",
- },
- Lint {
- name: "as_conversions",
- group: "restriction",
- desc: "using a potentially dangerous silent `as` conversion",
- deprecation: None,
- module: "as_conversions",
- },
- Lint {
- name: "assertions_on_constants",
- group: "style",
- desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`",
- deprecation: None,
- module: "assertions_on_constants",
- },
- Lint {
- name: "assign_op_pattern",
- group: "style",
- desc: "assigning the result of an operation on a variable to that same variable",
- deprecation: None,
- module: "assign_ops",
- },
- Lint {
- name: "async_yields_async",
- group: "correctness",
- desc: "async blocks that return a type that can be awaited",
- deprecation: None,
- module: "async_yields_async",
- },
- Lint {
- name: "await_holding_lock",
- group: "correctness",
- desc: "Inside an async function, holding a MutexGuard while calling await",
- deprecation: None,
- module: "await_holding_invalid",
- },
- Lint {
- name: "await_holding_refcell_ref",
- group: "correctness",
- desc: "Inside an async function, holding a RefCell ref while calling await",
- deprecation: None,
- module: "await_holding_invalid",
- },
- Lint {
- name: "bad_bit_mask",
- group: "correctness",
- desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`",
- deprecation: None,
- module: "bit_mask",
- },
- Lint {
- name: "bind_instead_of_map",
- group: "complexity",
- desc: "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "blacklisted_name",
- group: "style",
- desc: "usage of a blacklisted/placeholder name",
- deprecation: None,
- module: "blacklisted_name",
- },
- Lint {
- name: "blanket_clippy_restriction_lints",
- group: "style",
- desc: "enabling the complete restriction group",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "blocks_in_if_conditions",
- group: "style",
- desc: "useless or complex blocks that can be eliminated in conditions",
- deprecation: None,
- module: "blocks_in_if_conditions",
- },
- Lint {
- name: "bool_comparison",
- group: "complexity",
- desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`",
- deprecation: None,
- module: "needless_bool",
- },
- Lint {
- name: "borrow_interior_mutable_const",
- group: "style",
- desc: "referencing `const` with interior mutability",
- deprecation: None,
- module: "non_copy_const",
- },
- Lint {
- name: "borrowed_box",
- group: "complexity",
- desc: "a borrow of a boxed type",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "box_vec",
- group: "perf",
- desc: "usage of `Box<Vec<T>>`, vector elements are already on the heap",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "boxed_local",
- group: "perf",
- desc: "using `Box<T>` where unnecessary",
- deprecation: None,
- module: "escape",
- },
- Lint {
- name: "builtin_type_shadow",
- group: "style",
- desc: "shadowing a builtin type",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "cargo_common_metadata",
- group: "cargo",
- desc: "common metadata is defined in `Cargo.toml`",
- deprecation: None,
- module: "cargo_common_metadata",
- },
- Lint {
- name: "cast_lossless",
- group: "pedantic",
- desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "cast_possible_truncation",
- group: "pedantic",
- desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "cast_possible_wrap",
- group: "pedantic",
- desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "cast_precision_loss",
- group: "pedantic",
- desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "cast_ptr_alignment",
- group: "pedantic",
- desc: "cast from a pointer to a more-strictly-aligned pointer",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "cast_ref_to_mut",
- group: "correctness",
- desc: "a cast of reference to a mutable pointer",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "cast_sign_loss",
- group: "pedantic",
- desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "char_lit_as_u8",
- group: "complexity",
- desc: "casting a character literal to `u8` truncates",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "chars_last_cmp",
- group: "style",
- desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "chars_next_cmp",
- group: "style",
- desc: "using `.chars().next()` to check if a string starts with a char",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "checked_conversions",
- group: "pedantic",
- desc: "`try_from` could replace manual bounds checking when casting",
- deprecation: None,
- module: "checked_conversions",
- },
- Lint {
- name: "clone_double_ref",
- group: "correctness",
- desc: "using `clone` on `&&T`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "clone_on_copy",
- group: "complexity",
- desc: "using `clone` on a `Copy` type",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "clone_on_ref_ptr",
- group: "restriction",
- desc: "using \'clone\' on a ref-counted pointer",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "cmp_nan",
- group: "correctness",
- desc: "comparisons to `NAN`, which will always return false, probably not intended",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "cmp_null",
- group: "style",
- desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.",
- deprecation: None,
- module: "ptr",
- },
- Lint {
- name: "cmp_owned",
- group: "perf",
- desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "cognitive_complexity",
- group: "nursery",
- desc: "functions that should be split up into multiple functions",
- deprecation: None,
- module: "cognitive_complexity",
- },
- Lint {
- name: "collapsible_if",
- group: "style",
- desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)",
- deprecation: None,
- module: "collapsible_if",
- },
- Lint {
- name: "comparison_chain",
- group: "style",
- desc: "`if`s that can be rewritten with `match` and `cmp`",
- deprecation: None,
- module: "comparison_chain",
- },
- Lint {
- name: "comparison_to_empty",
- group: "style",
- desc: "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead",
- deprecation: None,
- module: "len_zero",
- },
- Lint {
- name: "copy_iterator",
- group: "pedantic",
- desc: "implementing `Iterator` on a `Copy` type",
- deprecation: None,
- module: "copy_iterator",
- },
- Lint {
- name: "create_dir",
- group: "restriction",
- desc: "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`",
- deprecation: None,
- module: "create_dir",
- },
- Lint {
- name: "crosspointer_transmute",
- group: "complexity",
- desc: "transmutes that have to or from types that are a pointer to the other",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "dbg_macro",
- group: "restriction",
- desc: "`dbg!` macro is intended as a debugging tool",
- deprecation: None,
- module: "dbg_macro",
- },
- Lint {
- name: "debug_assert_with_mut_call",
- group: "nursery",
- desc: "mutable arguments in `debug_assert{,_ne,_eq}!`",
- deprecation: None,
- module: "mutable_debug_assertion",
- },
- Lint {
- name: "decimal_literal_representation",
- group: "restriction",
- desc: "using decimal representation when hexadecimal would be better",
- deprecation: None,
- module: "literal_representation",
- },
- Lint {
- name: "declare_interior_mutable_const",
- group: "style",
- desc: "declaring `const` with interior mutability",
- deprecation: None,
- module: "non_copy_const",
- },
- Lint {
- name: "default_trait_access",
- group: "pedantic",
- desc: "checks for literal calls to `Default::default()`",
- deprecation: None,
- module: "default",
- },
- Lint {
- name: "deprecated_cfg_attr",
- group: "complexity",
- desc: "usage of `cfg_attr(rustfmt)` instead of tool attributes",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "deprecated_semver",
- group: "correctness",
- desc: "use of `#[deprecated(since = \"x\")]` where x is not semver",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "deref_addrof",
- group: "complexity",
- desc: "use of `*&` or `*&mut` in an expression",
- deprecation: None,
- module: "reference",
- },
- Lint {
- name: "derive_hash_xor_eq",
- group: "correctness",
- desc: "deriving `Hash` but implementing `PartialEq` explicitly",
- deprecation: None,
- module: "derive",
- },
- Lint {
- name: "derive_ord_xor_partial_ord",
- group: "correctness",
- desc: "deriving `Ord` but implementing `PartialOrd` explicitly",
- deprecation: None,
- module: "derive",
- },
- Lint {
- name: "disallowed_method",
- group: "nursery",
- desc: "use of a disallowed method call",
- deprecation: None,
- module: "disallowed_method",
- },
- Lint {
- name: "diverging_sub_expression",
- group: "complexity",
- desc: "whether an expression contains a diverging sub expression",
- deprecation: None,
- module: "eval_order_dependence",
- },
- Lint {
- name: "doc_markdown",
- group: "pedantic",
- desc: "presence of `_`, `::` or camel-case outside backticks in documentation",
- deprecation: None,
- module: "doc",
- },
- Lint {
- name: "double_comparisons",
- group: "complexity",
- desc: "unnecessary double comparisons that can be simplified",
- deprecation: None,
- module: "double_comparison",
- },
- Lint {
- name: "double_must_use",
- group: "style",
- desc: "`#[must_use]` attribute on a `#[must_use]`-returning function / method",
- deprecation: None,
- module: "functions",
- },
- Lint {
- name: "double_neg",
- group: "style",
- desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "double_parens",
- group: "complexity",
- desc: "Warn on unnecessary double parentheses",
- deprecation: None,
- module: "double_parens",
- },
- Lint {
- name: "drop_copy",
- group: "correctness",
- desc: "calls to `std::mem::drop` with a value that implements Copy",
- deprecation: None,
- module: "drop_forget_ref",
- },
- Lint {
- name: "drop_ref",
- group: "correctness",
- desc: "calls to `std::mem::drop` with a reference instead of an owned value",
- deprecation: None,
- module: "drop_forget_ref",
- },
- Lint {
- name: "duplicate_underscore_argument",
- group: "style",
- desc: "function arguments having names which only differ by an underscore",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "duration_subsec",
- group: "complexity",
- desc: "checks for calculation of subsecond microseconds or milliseconds",
- deprecation: None,
- module: "duration_subsec",
- },
- Lint {
- name: "else_if_without_else",
- group: "restriction",
- desc: "`if` expression with an `else if`, but without a final `else` branch",
- deprecation: None,
- module: "else_if_without_else",
- },
- Lint {
- name: "empty_enum",
- group: "pedantic",
- desc: "enum with no variants",
- deprecation: None,
- module: "empty_enum",
- },
- Lint {
- name: "empty_line_after_outer_attr",
- group: "nursery",
- desc: "empty line after outer attribute",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "empty_loop",
- group: "style",
- desc: "empty `loop {}`, which should block or sleep",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "enum_clike_unportable_variant",
- group: "correctness",
- desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`",
- deprecation: None,
- module: "enum_clike",
- },
- Lint {
- name: "enum_glob_use",
- group: "pedantic",
- desc: "use items that import all variants of an enum",
- deprecation: None,
- module: "wildcard_imports",
- },
- Lint {
- name: "enum_variant_names",
- group: "style",
- desc: "enums where all variants share a prefix/postfix",
- deprecation: None,
- module: "enum_variants",
- },
- Lint {
- name: "eq_op",
- group: "correctness",
- desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)",
- deprecation: None,
- module: "eq_op",
- },
- Lint {
- name: "erasing_op",
- group: "correctness",
- desc: "using erasing operations, e.g., `x * 0` or `y & 0`",
- deprecation: None,
- module: "erasing_op",
- },
- Lint {
- name: "eval_order_dependence",
- group: "complexity",
- desc: "whether a variable read occurs before a write depends on sub-expression evaluation order",
- deprecation: None,
- module: "eval_order_dependence",
- },
- Lint {
- name: "excessive_precision",
- group: "style",
- desc: "excessive precision for float literal",
- deprecation: None,
- module: "float_literal",
- },
- Lint {
- name: "exit",
- group: "restriction",
- desc: "`std::process::exit` is called, terminating the program",
- deprecation: None,
- module: "exit",
- },
- Lint {
- name: "expect_fun_call",
- group: "perf",
- desc: "using any `expect` method with a function call",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "expect_used",
- group: "restriction",
- desc: "using `.expect()` on `Result` or `Option`, which might be better handled",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "expl_impl_clone_on_copy",
- group: "pedantic",
- desc: "implementing `Clone` explicitly on `Copy` types",
- deprecation: None,
- module: "derive",
- },
- Lint {
- name: "explicit_counter_loop",
- group: "complexity",
- desc: "for-looping with an explicit counter when `_.enumerate()` would do",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "explicit_deref_methods",
- group: "pedantic",
- desc: "Explicit use of deref or deref_mut method while not in a method chain.",
- deprecation: None,
- module: "dereference",
- },
- Lint {
- name: "explicit_into_iter_loop",
- group: "pedantic",
- desc: "for-looping over `_.into_iter()` when `_` would do",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "explicit_iter_loop",
- group: "pedantic",
- desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "explicit_write",
- group: "complexity",
- desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work",
- deprecation: None,
- module: "explicit_write",
- },
- Lint {
- name: "extra_unused_lifetimes",
- group: "complexity",
- desc: "unused lifetimes in function definitions",
- deprecation: None,
- module: "lifetimes",
- },
- Lint {
- name: "fallible_impl_from",
- group: "nursery",
- desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`",
- deprecation: None,
- module: "fallible_impl_from",
- },
- Lint {
- name: "field_reassign_with_default",
- group: "style",
- desc: "binding initialized with Default should have its fields set in the initializer",
- deprecation: None,
- module: "default",
- },
- Lint {
- name: "filetype_is_file",
- group: "restriction",
- desc: "`FileType::is_file` is not recommended to test for readable file type",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "filter_map",
- group: "pedantic",
- desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "filter_map_next",
- group: "pedantic",
- desc: "using combination of `filter_map` and `next` which can usually be written as a single method call",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "filter_next",
- group: "complexity",
- desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "find_map",
- group: "pedantic",
- desc: "using a combination of `find` and `map` can usually be written as a single method call",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "flat_map_identity",
- group: "complexity",
- desc: "call to `flat_map` where `flatten` is sufficient",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "float_arithmetic",
- group: "restriction",
- desc: "any floating-point arithmetic statement",
- deprecation: None,
- module: "arithmetic",
- },
- Lint {
- name: "float_cmp",
- group: "correctness",
- desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "float_cmp_const",
- group: "restriction",
- desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "float_equality_without_abs",
- group: "correctness",
- desc: "float equality check without `.abs()`",
- deprecation: None,
- module: "float_equality_without_abs",
- },
- Lint {
- name: "fn_address_comparisons",
- group: "correctness",
- desc: "comparison with an address of a function item",
- deprecation: None,
- module: "unnamed_address",
- },
- Lint {
- name: "fn_params_excessive_bools",
- group: "pedantic",
- desc: "using too many bools in function parameters",
- deprecation: None,
- module: "excessive_bools",
- },
- Lint {
- name: "fn_to_numeric_cast",
- group: "style",
- desc: "casting a function pointer to a numeric type other than usize",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "fn_to_numeric_cast_with_truncation",
- group: "style",
- desc: "casting a function pointer to a numeric type not wide enough to store the address",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "for_kv_map",
- group: "style",
- desc: "looping on a map using `iter` when `keys` or `values` would do",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "for_loops_over_fallibles",
- group: "correctness",
- desc: "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "forget_copy",
- group: "correctness",
- desc: "calls to `std::mem::forget` with a value that implements Copy",
- deprecation: None,
- module: "drop_forget_ref",
- },
- Lint {
- name: "forget_ref",
- group: "correctness",
- desc: "calls to `std::mem::forget` with a reference instead of an owned value",
- deprecation: None,
- module: "drop_forget_ref",
- },
- Lint {
- name: "from_iter_instead_of_collect",
- group: "style",
- desc: "use `.collect()` instead of `::from_iter()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "future_not_send",
- group: "nursery",
- desc: "public Futures must be Send",
- deprecation: None,
- module: "future_not_send",
- },
- Lint {
- name: "get_last_with_len",
- group: "complexity",
- desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler",
- deprecation: None,
- module: "get_last_with_len",
- },
- Lint {
- name: "get_unwrap",
- group: "restriction",
- desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "identity_op",
- group: "complexity",
- desc: "using identity operations, e.g., `x + 0` or `y / 1`",
- deprecation: None,
- module: "identity_op",
- },
- Lint {
- name: "if_let_mutex",
- group: "correctness",
- desc: "locking a `Mutex` in an `if let` block can cause deadlocks",
- deprecation: None,
- module: "if_let_mutex",
- },
- Lint {
- name: "if_let_some_result",
- group: "style",
- desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead",
- deprecation: None,
- module: "if_let_some_result",
- },
- Lint {
- name: "if_not_else",
- group: "pedantic",
- desc: "`if` branches that could be swapped so no negation operation is necessary on the condition",
- deprecation: None,
- module: "if_not_else",
- },
- Lint {
- name: "if_same_then_else",
- group: "correctness",
- desc: "`if` with the same `then` and `else` blocks",
- deprecation: None,
- module: "copies",
- },
- Lint {
- name: "ifs_same_cond",
- group: "correctness",
- desc: "consecutive `if`s with the same condition",
- deprecation: None,
- module: "copies",
- },
- Lint {
- name: "implicit_hasher",
- group: "pedantic",
- desc: "missing generalization over different hashers",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "implicit_return",
- group: "restriction",
- desc: "use a return statement like `return expr` instead of an expression",
- deprecation: None,
- module: "implicit_return",
- },
- Lint {
- name: "implicit_saturating_sub",
- group: "pedantic",
- desc: "Perform saturating subtraction instead of implicitly checking lower bound of data type",
- deprecation: None,
- module: "implicit_saturating_sub",
- },
- Lint {
- name: "imprecise_flops",
- group: "nursery",
- desc: "usage of imprecise floating point operations",
- deprecation: None,
- module: "floating_point_arithmetic",
- },
- Lint {
- name: "inconsistent_digit_grouping",
- group: "style",
- desc: "integer literals with digits grouped inconsistently",
- deprecation: None,
- module: "literal_representation",
- },
- Lint {
- name: "indexing_slicing",
- group: "restriction",
- desc: "indexing/slicing usage",
- deprecation: None,
- module: "indexing_slicing",
- },
- Lint {
- name: "ineffective_bit_mask",
- group: "correctness",
- desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`",
- deprecation: None,
- module: "bit_mask",
- },
- Lint {
- name: "inefficient_to_string",
- group: "pedantic",
- desc: "using `to_string` on `&&T` where `T: ToString`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "infallible_destructuring_match",
- group: "style",
- desc: "a `match` statement with a single infallible arm instead of a `let`",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "infinite_iter",
- group: "correctness",
- desc: "infinite iteration",
- deprecation: None,
- module: "infinite_iter",
- },
- Lint {
- name: "inherent_to_string",
- group: "style",
- desc: "type implements inherent method `to_string()`, but should instead implement the `Display` trait",
- deprecation: None,
- module: "inherent_to_string",
- },
- Lint {
- name: "inherent_to_string_shadow_display",
- group: "correctness",
- desc: "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait",
- deprecation: None,
- module: "inherent_to_string",
- },
- Lint {
- name: "inline_always",
- group: "pedantic",
- desc: "use of `#[inline(always)]`",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "inline_asm_x86_att_syntax",
- group: "restriction",
- desc: "prefer Intel x86 assembly syntax",
- deprecation: None,
- module: "asm_syntax",
- },
- Lint {
- name: "inline_asm_x86_intel_syntax",
- group: "restriction",
- desc: "prefer AT&T x86 assembly syntax",
- deprecation: None,
- module: "asm_syntax",
- },
- Lint {
- name: "inline_fn_without_body",
- group: "correctness",
- desc: "use of `#[inline]` on trait methods without bodies",
- deprecation: None,
- module: "inline_fn_without_body",
- },
- Lint {
- name: "int_plus_one",
- group: "complexity",
- desc: "instead of using `x >= y + 1`, use `x > y`",
- deprecation: None,
- module: "int_plus_one",
- },
- Lint {
- name: "integer_arithmetic",
- group: "restriction",
- desc: "any integer arithmetic expression which could overflow or panic",
- deprecation: None,
- module: "arithmetic",
- },
- Lint {
- name: "integer_division",
- group: "restriction",
- desc: "integer division may cause loss of precision",
- deprecation: None,
- module: "integer_division",
- },
- Lint {
- name: "into_iter_on_ref",
- group: "style",
- desc: "using `.into_iter()` on a reference",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "invalid_atomic_ordering",
- group: "correctness",
- desc: "usage of invalid atomic ordering in atomic operations and memory fences",
- deprecation: None,
- module: "atomic_ordering",
- },
- Lint {
- name: "invalid_regex",
- group: "correctness",
- desc: "invalid regular expressions",
- deprecation: None,
- module: "regex",
- },
- Lint {
- name: "invalid_upcast_comparisons",
- group: "pedantic",
- desc: "a comparison involving an upcast which is always true or false",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "invisible_characters",
- group: "correctness",
- desc: "using an invisible character in a string literal, which is confusing",
- deprecation: None,
- module: "unicode",
- },
- Lint {
- name: "items_after_statements",
- group: "pedantic",
- desc: "blocks where an item comes after a statement",
- deprecation: None,
- module: "items_after_statements",
- },
- Lint {
- name: "iter_cloned_collect",
- group: "style",
- desc: "using `.cloned().collect()` on slice to create a `Vec`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "iter_next_loop",
- group: "correctness",
- desc: "for-looping over `_.next()` which is probably not intended",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "iter_next_slice",
- group: "style",
- desc: "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "iter_nth",
- group: "perf",
- desc: "using `.iter().nth()` on a standard library type with O(1) element access",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "iter_nth_zero",
- group: "style",
- desc: "replace `iter.nth(0)` with `iter.next()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "iter_skip_next",
- group: "style",
- desc: "using `.skip(x).next()` on an iterator",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "iterator_step_by_zero",
- group: "correctness",
- desc: "using `Iterator::step_by(0)`, which will panic at runtime",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "just_underscores_and_digits",
- group: "style",
- desc: "unclear name",
- deprecation: None,
- module: "non_expressive_names",
- },
- Lint {
- name: "large_const_arrays",
- group: "perf",
- desc: "large non-scalar const array may cause performance overhead",
- deprecation: None,
- module: "large_const_arrays",
- },
- Lint {
- name: "large_digit_groups",
- group: "pedantic",
- desc: "grouping digits into groups that are too large",
- deprecation: None,
- module: "literal_representation",
- },
- Lint {
- name: "large_enum_variant",
- group: "perf",
- desc: "large size difference between variants on an enum",
- deprecation: None,
- module: "large_enum_variant",
- },
- Lint {
- name: "large_stack_arrays",
- group: "pedantic",
- desc: "allocating large arrays on stack may cause stack overflow",
- deprecation: None,
- module: "large_stack_arrays",
- },
- Lint {
- name: "large_types_passed_by_value",
- group: "pedantic",
- desc: "functions taking large arguments by value",
- deprecation: None,
- module: "pass_by_ref_or_value",
- },
- Lint {
- name: "len_without_is_empty",
- group: "style",
- desc: "traits or impls with a public `len` method but no corresponding `is_empty` method",
- deprecation: None,
- module: "len_zero",
- },
- Lint {
- name: "len_zero",
- group: "style",
- desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead",
- deprecation: None,
- module: "len_zero",
- },
- Lint {
- name: "let_and_return",
- group: "style",
- desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block",
- deprecation: None,
- module: "returns",
- },
- Lint {
- name: "let_underscore_lock",
- group: "correctness",
- desc: "non-binding let on a synchronization lock",
- deprecation: None,
- module: "let_underscore",
- },
- Lint {
- name: "let_underscore_must_use",
- group: "restriction",
- desc: "non-binding let on a `#[must_use]` expression",
- deprecation: None,
- module: "let_underscore",
- },
- Lint {
- name: "let_unit_value",
- group: "pedantic",
- desc: "creating a `let` binding to a value of unit type, which usually can\'t be used afterwards",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "linkedlist",
- group: "pedantic",
- desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "logic_bug",
- group: "correctness",
- desc: "boolean expressions that contain terminals which can be eliminated",
- deprecation: None,
- module: "booleans",
- },
- Lint {
- name: "lossy_float_literal",
- group: "restriction",
- desc: "lossy whole number float literals",
- deprecation: None,
- module: "float_literal",
- },
- Lint {
- name: "macro_use_imports",
- group: "pedantic",
- desc: "#[macro_use] is no longer needed",
- deprecation: None,
- module: "macro_use",
- },
- Lint {
- name: "main_recursion",
- group: "style",
- desc: "recursion using the entrypoint",
- deprecation: None,
- module: "main_recursion",
- },
- Lint {
- name: "manual_async_fn",
- group: "style",
- desc: "manual implementations of `async` functions can be simplified using the dedicated syntax",
- deprecation: None,
- module: "manual_async_fn",
- },
- Lint {
- name: "manual_memcpy",
- group: "perf",
- desc: "manually copying items between slices",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "manual_non_exhaustive",
- group: "style",
- desc: "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]",
- deprecation: None,
- module: "manual_non_exhaustive",
- },
- Lint {
- name: "manual_ok_or",
- group: "pedantic",
- desc: "finds patterns that can be encoded more concisely with `Option::ok_or`",
- deprecation: None,
- module: "manual_ok_or",
- },
- Lint {
- name: "manual_range_contains",
- group: "style",
- desc: "manually reimplementing {`Range`, `RangeInclusive`}`::contains`",
- deprecation: None,
- module: "ranges",
- },
- Lint {
- name: "manual_saturating_arithmetic",
- group: "style",
- desc: "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "manual_strip",
- group: "complexity",
- desc: "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing",
- deprecation: None,
- module: "manual_strip",
- },
- Lint {
- name: "manual_swap",
- group: "complexity",
- desc: "manual swap of two variables",
- deprecation: None,
- module: "swap",
- },
- Lint {
- name: "manual_unwrap_or",
- group: "complexity",
- desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or` or `Result::unwrap_or`",
- deprecation: None,
- module: "manual_unwrap_or",
- },
- Lint {
- name: "many_single_char_names",
- group: "style",
- desc: "too many single character bindings",
- deprecation: None,
- module: "non_expressive_names",
- },
- Lint {
- name: "map_clone",
- group: "style",
- desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types",
- deprecation: None,
- module: "map_clone",
- },
- Lint {
- name: "map_collect_result_unit",
- group: "style",
- desc: "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "map_entry",
- group: "perf",
- desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`",
- deprecation: None,
- module: "entry",
- },
- Lint {
- name: "map_err_ignore",
- group: "pedantic",
- desc: "`map_err` should not ignore the original error",
- deprecation: None,
- module: "map_err_ignore",
- },
- Lint {
- name: "map_flatten",
- group: "pedantic",
- desc: "using combinations of `flatten` and `map` which can usually be written as a single method call",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "map_identity",
- group: "complexity",
- desc: "using iterator.map(|x| x)",
- deprecation: None,
- module: "map_identity",
- },
- Lint {
- name: "map_unwrap_or",
- group: "pedantic",
- desc: "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "match_as_ref",
- group: "complexity",
- desc: "a `match` on an Option value instead of using `as_ref()` or `as_mut`",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_bool",
- group: "pedantic",
- desc: "a `match` on a boolean expression instead of an `if..else` block",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_like_matches_macro",
- group: "style",
- desc: "a match that could be written with the matches! macro",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_on_vec_items",
- group: "pedantic",
- desc: "matching on vector elements can panic",
- deprecation: None,
- module: "match_on_vec_items",
- },
- Lint {
- name: "match_overlapping_arm",
- group: "style",
- desc: "a `match` with overlapping arms",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_ref_pats",
- group: "style",
- desc: "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_same_arms",
- group: "pedantic",
- desc: "`match` with identical arm bodies",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_single_binding",
- group: "complexity",
- desc: "a match with a single binding instead of using `let` statement",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_wild_err_arm",
- group: "pedantic",
- desc: "a `match` with `Err(_)` arm and take drastic actions",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "match_wildcard_for_single_variants",
- group: "pedantic",
- desc: "a wildcard enum match for a single variant",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "maybe_infinite_iter",
- group: "pedantic",
- desc: "possible infinite iteration",
- deprecation: None,
- module: "infinite_iter",
- },
- Lint {
- name: "mem_discriminant_non_enum",
- group: "correctness",
- desc: "calling `mem::descriminant` on non-enum type",
- deprecation: None,
- module: "mem_discriminant",
- },
- Lint {
- name: "mem_forget",
- group: "restriction",
- desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks",
- deprecation: None,
- module: "mem_forget",
- },
- Lint {
- name: "mem_replace_option_with_none",
- group: "style",
- desc: "replacing an `Option` with `None` instead of `take()`",
- deprecation: None,
- module: "mem_replace",
- },
- Lint {
- name: "mem_replace_with_default",
- group: "style",
- desc: "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`",
- deprecation: None,
- module: "mem_replace",
- },
- Lint {
- name: "mem_replace_with_uninit",
- group: "correctness",
- desc: "`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`",
- deprecation: None,
- module: "mem_replace",
- },
- Lint {
- name: "min_max",
- group: "correctness",
- desc: "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant",
- deprecation: None,
- module: "minmax",
- },
- Lint {
- name: "mismatched_target_os",
- group: "correctness",
- desc: "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "misrefactored_assign_op",
- group: "complexity",
- desc: "having a variable on both sides of an assign op",
- deprecation: None,
- module: "assign_ops",
- },
- Lint {
- name: "missing_const_for_fn",
- group: "nursery",
- desc: "Lint functions definitions that could be made `const fn`",
- deprecation: None,
- module: "missing_const_for_fn",
- },
- Lint {
- name: "missing_docs_in_private_items",
- group: "restriction",
- desc: "detects missing documentation for public and private members",
- deprecation: None,
- module: "missing_doc",
- },
- Lint {
- name: "missing_errors_doc",
- group: "pedantic",
- desc: "`pub fn` returns `Result` without `# Errors` in doc comment",
- deprecation: None,
- module: "doc",
- },
- Lint {
- name: "missing_inline_in_public_items",
- group: "restriction",
- desc: "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)",
- deprecation: None,
- module: "missing_inline",
- },
- Lint {
- name: "missing_safety_doc",
- group: "style",
- desc: "`pub unsafe fn` without `# Safety` docs",
- deprecation: None,
- module: "doc",
- },
- Lint {
- name: "mistyped_literal_suffixes",
- group: "correctness",
- desc: "mistyped literal suffix",
- deprecation: None,
- module: "literal_representation",
- },
- Lint {
- name: "mixed_case_hex_literals",
- group: "style",
- desc: "hex literals whose letter digits are not consistently upper- or lowercased",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "module_inception",
- group: "style",
- desc: "modules that have the same name as their parent module",
- deprecation: None,
- module: "enum_variants",
- },
- Lint {
- name: "module_name_repetitions",
- group: "pedantic",
- desc: "type names prefixed/postfixed with their containing module\'s name",
- deprecation: None,
- module: "enum_variants",
- },
- Lint {
- name: "modulo_arithmetic",
- group: "restriction",
- desc: "any modulo arithmetic statement",
- deprecation: None,
- module: "modulo_arithmetic",
- },
- Lint {
- name: "modulo_one",
- group: "correctness",
- desc: "taking a number modulo 1, which always returns 0",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "multiple_crate_versions",
- group: "cargo",
- desc: "multiple versions of the same crate being used",
- deprecation: None,
- module: "multiple_crate_versions",
- },
- Lint {
- name: "multiple_inherent_impl",
- group: "restriction",
- desc: "Multiple inherent impl that could be grouped",
- deprecation: None,
- module: "inherent_impl",
- },
- Lint {
- name: "must_use_candidate",
- group: "pedantic",
- desc: "function or method that could take a `#[must_use]` attribute",
- deprecation: None,
- module: "functions",
- },
- Lint {
- name: "must_use_unit",
- group: "style",
- desc: "`#[must_use]` attribute on a unit-returning function / method",
- deprecation: None,
- module: "functions",
- },
- Lint {
- name: "mut_from_ref",
- group: "correctness",
- desc: "fns that create mutable refs from immutable ref args",
- deprecation: None,
- module: "ptr",
- },
- Lint {
- name: "mut_mut",
- group: "pedantic",
- desc: "usage of double-mut refs, e.g., `&mut &mut ...`",
- deprecation: None,
- module: "mut_mut",
- },
- Lint {
- name: "mut_mutex_lock",
- group: "style",
- desc: "`&mut Mutex::lock` does unnecessary locking",
- deprecation: None,
- module: "mut_mutex_lock",
- },
- Lint {
- name: "mut_range_bound",
- group: "complexity",
- desc: "for loop over a range where one of the bounds is a mutable variable",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "mutable_key_type",
- group: "correctness",
- desc: "Check for mutable `Map`/`Set` key type",
- deprecation: None,
- module: "mut_key",
- },
- Lint {
- name: "mutex_atomic",
- group: "perf",
- desc: "using a mutex where an atomic value could be used instead",
- deprecation: None,
- module: "mutex_atomic",
- },
- Lint {
- name: "mutex_integer",
- group: "nursery",
- desc: "using a mutex for an integer type",
- deprecation: None,
- module: "mutex_atomic",
- },
- Lint {
- name: "naive_bytecount",
- group: "perf",
- desc: "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values",
- deprecation: None,
- module: "bytecount",
- },
- Lint {
- name: "needless_arbitrary_self_type",
- group: "complexity",
- desc: "type of `self` parameter is already by default `Self`",
- deprecation: None,
- module: "needless_arbitrary_self_type",
- },
- Lint {
- name: "needless_bool",
- group: "complexity",
- desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`",
- deprecation: None,
- module: "needless_bool",
- },
- Lint {
- name: "needless_borrow",
- group: "nursery",
- desc: "taking a reference that is going to be automatically dereferenced",
- deprecation: None,
- module: "needless_borrow",
- },
- Lint {
- name: "needless_borrowed_reference",
- group: "complexity",
- desc: "taking a needless borrowed reference",
- deprecation: None,
- module: "needless_borrowed_ref",
- },
- Lint {
- name: "needless_collect",
- group: "perf",
- desc: "collecting an iterator when collect is not needed",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "needless_continue",
- group: "pedantic",
- desc: "`continue` statements that can be replaced by a rearrangement of code",
- deprecation: None,
- module: "needless_continue",
- },
- Lint {
- name: "needless_doctest_main",
- group: "style",
- desc: "presence of `fn main() {` in code examples",
- deprecation: None,
- module: "doc",
- },
- Lint {
- name: "needless_lifetimes",
- group: "complexity",
- desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them",
- deprecation: None,
- module: "lifetimes",
- },
- Lint {
- name: "needless_pass_by_value",
- group: "pedantic",
- desc: "functions taking arguments by value, but not consuming them in its body",
- deprecation: None,
- module: "needless_pass_by_value",
- },
- Lint {
- name: "needless_range_loop",
- group: "style",
- desc: "for-looping over a range of indices where an iterator over items would do",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "needless_return",
- group: "style",
- desc: "using a return statement like `return expr;` where an expression would suffice",
- deprecation: None,
- module: "returns",
- },
- Lint {
- name: "needless_update",
- group: "complexity",
- desc: "using `Foo { ..base }` when there are no missing fields",
- deprecation: None,
- module: "needless_update",
- },
- Lint {
- name: "neg_cmp_op_on_partial_ord",
- group: "complexity",
- desc: "The use of negated comparison operators on partially ordered types may produce confusing code.",
- deprecation: None,
- module: "neg_cmp_op_on_partial_ord",
- },
- Lint {
- name: "neg_multiply",
- group: "style",
- desc: "multiplying integers with `-1`",
- deprecation: None,
- module: "neg_multiply",
- },
- Lint {
- name: "never_loop",
- group: "correctness",
- desc: "any loop that will always `break` or `return`",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "new_ret_no_self",
- group: "style",
- desc: "not returning type containing `Self` in a `new` method",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "new_without_default",
- group: "style",
- desc: "`fn new() -> Self` method without `Default` implementation",
- deprecation: None,
- module: "new_without_default",
- },
- Lint {
- name: "no_effect",
- group: "complexity",
- desc: "statements with no effect",
- deprecation: None,
- module: "no_effect",
- },
- Lint {
- name: "non_ascii_literal",
- group: "pedantic",
- desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape",
- deprecation: None,
- module: "unicode",
- },
- Lint {
- name: "nonminimal_bool",
- group: "complexity",
- desc: "boolean expressions that can be written more concisely",
- deprecation: None,
- module: "booleans",
- },
- Lint {
- name: "nonsensical_open_options",
- group: "correctness",
- desc: "nonsensical combination of options for opening a file",
- deprecation: None,
- module: "open_options",
- },
- Lint {
- name: "not_unsafe_ptr_arg_deref",
- group: "correctness",
- desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`",
- deprecation: None,
- module: "functions",
- },
- Lint {
- name: "ok_expect",
- group: "style",
- desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "op_ref",
- group: "style",
- desc: "taking a reference to satisfy the type constraints on `==`",
- deprecation: None,
- module: "eq_op",
- },
- Lint {
- name: "option_as_ref_deref",
- group: "complexity",
- desc: "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "option_env_unwrap",
- group: "correctness",
- desc: "using `option_env!(...).unwrap()` to get environment variable",
- deprecation: None,
- module: "option_env_unwrap",
- },
- Lint {
- name: "option_if_let_else",
- group: "pedantic",
- desc: "reimplementation of Option::map_or",
- deprecation: None,
- module: "option_if_let_else",
- },
- Lint {
- name: "option_map_or_none",
- group: "style",
- desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "option_map_unit_fn",
- group: "complexity",
- desc: "using `option.map(f)`, where `f` is a function or closure that returns `()`",
- deprecation: None,
- module: "map_unit_fn",
- },
- Lint {
- name: "option_option",
- group: "pedantic",
- desc: "usage of `Option<Option<T>>`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "or_fun_call",
- group: "perf",
- desc: "using any `*or` method with a function call, which suggests `*or_else`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "out_of_bounds_indexing",
- group: "correctness",
- desc: "out of bounds constant indexing",
- deprecation: None,
- module: "indexing_slicing",
- },
- Lint {
- name: "overflow_check_conditional",
- group: "complexity",
- desc: "overflow checks inspired by C which are likely to panic",
- deprecation: None,
- module: "overflow_check_conditional",
- },
- Lint {
- name: "panic",
- group: "restriction",
- desc: "usage of the `panic!` macro",
- deprecation: None,
- module: "panic_unimplemented",
- },
- Lint {
- name: "panic_in_result_fn",
- group: "restriction",
- desc: "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` ",
- deprecation: None,
- module: "panic_in_result_fn",
- },
- Lint {
- name: "panic_params",
- group: "style",
- desc: "missing parameters in `panic!` calls",
- deprecation: None,
- module: "panic_unimplemented",
- },
- Lint {
- name: "panicking_unwrap",
- group: "correctness",
- desc: "checks for calls of `unwrap[_err]()` that will always fail",
- deprecation: None,
- module: "unwrap",
- },
- Lint {
- name: "partialeq_ne_impl",
- group: "complexity",
- desc: "re-implementing `PartialEq::ne`",
- deprecation: None,
- module: "partialeq_ne_impl",
- },
- Lint {
- name: "path_buf_push_overwrite",
- group: "nursery",
- desc: "calling `push` with file system root on `PathBuf` can overwrite it",
- deprecation: None,
- module: "path_buf_push_overwrite",
- },
- Lint {
- name: "pattern_type_mismatch",
- group: "restriction",
- desc: "type of pattern does not match the expression type",
- deprecation: None,
- module: "pattern_type_mismatch",
- },
- Lint {
- name: "possible_missing_comma",
- group: "correctness",
- desc: "possible missing comma in array",
- deprecation: None,
- module: "formatting",
- },
- Lint {
- name: "precedence",
- group: "complexity",
- desc: "operations where precedence may be unclear",
- deprecation: None,
- module: "precedence",
- },
- Lint {
- name: "print_literal",
- group: "style",
- desc: "printing a literal with a format string",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "print_stdout",
- group: "restriction",
- desc: "printing on stdout",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "print_with_newline",
- group: "style",
- desc: "using `print!()` with a format string that ends in a single newline",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "println_empty_string",
- group: "style",
- desc: "using `println!(\"\")` with an empty string",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "ptr_arg",
- group: "style",
- desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively",
- deprecation: None,
- module: "ptr",
- },
- Lint {
- name: "ptr_eq",
- group: "style",
- desc: "use `std::ptr::eq` when comparing raw pointers",
- deprecation: None,
- module: "ptr_eq",
- },
- Lint {
- name: "ptr_offset_with_cast",
- group: "complexity",
- desc: "unneeded pointer offset cast",
- deprecation: None,
- module: "ptr_offset_with_cast",
- },
- Lint {
- name: "pub_enum_variant_names",
- group: "pedantic",
- desc: "public enums where all variants share a prefix/postfix",
- deprecation: None,
- module: "enum_variants",
- },
- Lint {
- name: "question_mark",
- group: "style",
- desc: "checks for expressions that could be replaced by the question mark operator",
- deprecation: None,
- module: "question_mark",
- },
- Lint {
- name: "range_minus_one",
- group: "pedantic",
- desc: "`x..=(y-1)` reads better as `x..y`",
- deprecation: None,
- module: "ranges",
- },
- Lint {
- name: "range_plus_one",
- group: "pedantic",
- desc: "`x..(y+1)` reads better as `x..=y`",
- deprecation: None,
- module: "ranges",
- },
- Lint {
- name: "range_zip_with_len",
- group: "complexity",
- desc: "zipping iterator with a range when `enumerate()` would do",
- deprecation: None,
- module: "ranges",
- },
- Lint {
- name: "rc_buffer",
- group: "restriction",
- desc: "shared ownership of a buffer type",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "redundant_allocation",
- group: "perf",
- desc: "redundant allocation",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "redundant_clone",
- group: "perf",
- desc: "`clone()` of an owned value that is going to be dropped immediately",
- deprecation: None,
- module: "redundant_clone",
- },
- Lint {
- name: "redundant_closure",
- group: "style",
- desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)",
- deprecation: None,
- module: "eta_reduction",
- },
- Lint {
- name: "redundant_closure_call",
- group: "complexity",
- desc: "throwaway closures called in the expression they are defined",
- deprecation: None,
- module: "redundant_closure_call",
- },
- Lint {
- name: "redundant_closure_for_method_calls",
- group: "pedantic",
- desc: "redundant closures for method calls",
- deprecation: None,
- module: "eta_reduction",
- },
- Lint {
- name: "redundant_field_names",
- group: "style",
- desc: "checks for fields in struct literals where shorthands could be used",
- deprecation: None,
- module: "redundant_field_names",
- },
- Lint {
- name: "redundant_pattern",
- group: "style",
- desc: "using `name @ _` in a pattern",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "redundant_pattern_matching",
- group: "style",
- desc: "use the proper utility function avoiding an `if let`",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "redundant_pub_crate",
- group: "nursery",
- desc: "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them.",
- deprecation: None,
- module: "redundant_pub_crate",
- },
- Lint {
- name: "redundant_static_lifetimes",
- group: "style",
- desc: "Using explicit `\'static` lifetime for constants or statics when elision rules would allow omitting them.",
- deprecation: None,
- module: "redundant_static_lifetimes",
- },
- Lint {
- name: "ref_in_deref",
- group: "complexity",
- desc: "Use of reference in auto dereference expression.",
- deprecation: None,
- module: "reference",
- },
- Lint {
- name: "ref_option_ref",
- group: "pedantic",
- desc: "use `Option<&T>` instead of `&Option<&T>`",
- deprecation: None,
- module: "ref_option_ref",
- },
- Lint {
- name: "repeat_once",
- group: "complexity",
- desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ",
- deprecation: None,
- module: "repeat_once",
- },
- Lint {
- name: "rest_pat_in_fully_bound_structs",
- group: "restriction",
- desc: "a match on a struct that binds all fields but still uses the wildcard pattern",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "result_map_or_into_option",
- group: "style",
- desc: "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "result_map_unit_fn",
- group: "complexity",
- desc: "using `result.map(f)`, where `f` is a function or closure that returns `()`",
- deprecation: None,
- module: "map_unit_fn",
- },
- Lint {
- name: "result_unit_err",
- group: "style",
- desc: "public function returning `Result` with an `Err` type of `()`",
- deprecation: None,
- module: "functions",
- },
- Lint {
- name: "reversed_empty_ranges",
- group: "correctness",
- desc: "reversing the limits of range expressions, resulting in empty ranges",
- deprecation: None,
- module: "ranges",
- },
- Lint {
- name: "same_functions_in_if_condition",
- group: "pedantic",
- desc: "consecutive `if`s with the same function call",
- deprecation: None,
- module: "copies",
- },
- Lint {
- name: "same_item_push",
- group: "style",
- desc: "the same item is pushed inside of a for loop",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "search_is_some",
- group: "complexity",
- desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "self_assignment",
- group: "correctness",
- desc: "explicit self-assignment",
- deprecation: None,
- module: "self_assignment",
- },
- Lint {
- name: "serde_api_misuse",
- group: "correctness",
- desc: "various things that will negatively affect your serde experience",
- deprecation: None,
- module: "serde_api",
- },
- Lint {
- name: "shadow_reuse",
- group: "restriction",
- desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`",
- deprecation: None,
- module: "shadow",
- },
- Lint {
- name: "shadow_same",
- group: "restriction",
- desc: "rebinding a name to itself, e.g., `let mut x = &mut x`",
- deprecation: None,
- module: "shadow",
- },
- Lint {
- name: "shadow_unrelated",
- group: "pedantic",
- desc: "rebinding a name without even using the original value",
- deprecation: None,
- module: "shadow",
- },
- Lint {
- name: "short_circuit_statement",
- group: "complexity",
- desc: "using a short circuit boolean condition as a statement",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "should_implement_trait",
- group: "style",
- desc: "defining a method that should be implementing a std trait",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "similar_names",
- group: "pedantic",
- desc: "similarly named items and bindings",
- deprecation: None,
- module: "non_expressive_names",
- },
- Lint {
- name: "single_char_add_str",
- group: "style",
- desc: "`push_str()` or `insert_str()` used with a single-character string literal as parameter",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "single_char_pattern",
- group: "perf",
- desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "single_component_path_imports",
- group: "style",
- desc: "imports with single component path are redundant",
- deprecation: None,
- module: "single_component_path_imports",
- },
- Lint {
- name: "single_element_loop",
- group: "complexity",
- desc: "there is no reason to have a single element loop",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "single_match",
- group: "style",
- desc: "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "single_match_else",
- group: "pedantic",
- desc: "a `match` statement with two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "skip_while_next",
- group: "complexity",
- desc: "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "slow_vector_initialization",
- group: "perf",
- desc: "slow vector initialization",
- deprecation: None,
- module: "slow_vector_initialization",
- },
- Lint {
- name: "stable_sort_primitive",
- group: "perf",
- desc: "use of sort() when sort_unstable() is equivalent",
- deprecation: None,
- module: "stable_sort_primitive",
- },
- Lint {
- name: "string_add",
- group: "restriction",
- desc: "using `x + ..` where x is a `String` instead of `push_str()`",
- deprecation: None,
- module: "strings",
- },
- Lint {
- name: "string_add_assign",
- group: "pedantic",
- desc: "using `x = x + ..` where x is a `String` instead of `push_str()`",
- deprecation: None,
- module: "strings",
- },
- Lint {
- name: "string_extend_chars",
- group: "style",
- desc: "using `x.extend(s.chars())` where s is a `&str` or `String`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "string_lit_as_bytes",
- group: "nursery",
- desc: "calling `as_bytes` on a string literal instead of using a byte string literal",
- deprecation: None,
- module: "strings",
- },
- Lint {
- name: "struct_excessive_bools",
- group: "pedantic",
- desc: "using too many bools in a struct",
- deprecation: None,
- module: "excessive_bools",
- },
- Lint {
- name: "suboptimal_flops",
- group: "nursery",
- desc: "usage of sub-optimal floating point operations",
- deprecation: None,
- module: "floating_point_arithmetic",
- },
- Lint {
- name: "suspicious_arithmetic_impl",
- group: "correctness",
- desc: "suspicious use of operators in impl of arithmetic trait",
- deprecation: None,
- module: "suspicious_trait_impl",
- },
- Lint {
- name: "suspicious_assignment_formatting",
- group: "style",
- desc: "suspicious formatting of `*=`, `-=` or `!=`",
- deprecation: None,
- module: "formatting",
- },
- Lint {
- name: "suspicious_else_formatting",
- group: "style",
- desc: "suspicious formatting of `else`",
- deprecation: None,
- module: "formatting",
- },
- Lint {
- name: "suspicious_map",
- group: "complexity",
- desc: "suspicious usage of map",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "suspicious_op_assign_impl",
- group: "correctness",
- desc: "suspicious use of operators in impl of OpAssign trait",
- deprecation: None,
- module: "suspicious_trait_impl",
- },
- Lint {
- name: "suspicious_unary_op_formatting",
- group: "style",
- desc: "suspicious formatting of unary `-` or `!` on the RHS of a BinOp",
- deprecation: None,
- module: "formatting",
- },
- Lint {
- name: "tabs_in_doc_comments",
- group: "style",
- desc: "using tabs in doc comments is not recommended",
- deprecation: None,
- module: "tabs_in_doc_comments",
- },
- Lint {
- name: "temporary_assignment",
- group: "complexity",
- desc: "assignments to temporaries",
- deprecation: None,
- module: "temporary_assignment",
- },
- Lint {
- name: "to_digit_is_some",
- group: "style",
- desc: "`char.is_digit()` is clearer",
- deprecation: None,
- module: "to_digit_is_some",
- },
- Lint {
- name: "to_string_in_display",
- group: "correctness",
- desc: "`to_string` method used while implementing `Display` trait",
- deprecation: None,
- module: "to_string_in_display",
- },
- Lint {
- name: "todo",
- group: "restriction",
- desc: "`todo!` should not be present in production code",
- deprecation: None,
- module: "panic_unimplemented",
- },
- Lint {
- name: "too_many_arguments",
- group: "complexity",
- desc: "functions with too many arguments",
- deprecation: None,
- module: "functions",
- },
- Lint {
- name: "too_many_lines",
- group: "pedantic",
- desc: "functions with too many lines",
- deprecation: None,
- module: "functions",
- },
- Lint {
- name: "toplevel_ref_arg",
- group: "style",
- desc: "an entire binding declared as `ref`, in a function argument or a `let` statement",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "trait_duplication_in_bounds",
- group: "pedantic",
- desc: "Check if the same trait bounds are specified twice during a function declaration",
- deprecation: None,
- module: "trait_bounds",
- },
- Lint {
- name: "transmute_bytes_to_str",
- group: "complexity",
- desc: "transmutes from a `&[u8]` to a `&str`",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmute_float_to_int",
- group: "complexity",
- desc: "transmutes from a float to an integer",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmute_int_to_bool",
- group: "complexity",
- desc: "transmutes from an integer to a `bool`",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmute_int_to_char",
- group: "complexity",
- desc: "transmutes from an integer to a `char`",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmute_int_to_float",
- group: "complexity",
- desc: "transmutes from an integer to a float",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmute_ptr_to_ptr",
- group: "complexity",
- desc: "transmutes from a pointer to a pointer / a reference to a reference",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmute_ptr_to_ref",
- group: "complexity",
- desc: "transmutes from a pointer to a reference type",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmutes_expressible_as_ptr_casts",
- group: "complexity",
- desc: "transmutes that could be a pointer cast",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "transmuting_null",
- group: "correctness",
- desc: "transmutes from a null pointer to a reference, which is undefined behavior",
- deprecation: None,
- module: "transmuting_null",
- },
- Lint {
- name: "trivial_regex",
- group: "style",
- desc: "trivial regular expressions",
- deprecation: None,
- module: "regex",
- },
- Lint {
- name: "trivially_copy_pass_by_ref",
- group: "pedantic",
- desc: "functions taking small copyable arguments by reference",
- deprecation: None,
- module: "pass_by_ref_or_value",
- },
- Lint {
- name: "try_err",
- group: "style",
- desc: "return errors explicitly rather than hiding them behind a `?`",
- deprecation: None,
- module: "try_err",
- },
- Lint {
- name: "type_complexity",
- group: "complexity",
- desc: "usage of very complex types that might be better factored into `type` definitions",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "type_repetition_in_bounds",
- group: "pedantic",
- desc: "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`",
- deprecation: None,
- module: "trait_bounds",
- },
- Lint {
- name: "undropped_manually_drops",
- group: "correctness",
- desc: "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value",
- deprecation: None,
- module: "undropped_manually_drops",
- },
- Lint {
- name: "unicode_not_nfc",
- group: "pedantic",
- desc: "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)",
- deprecation: None,
- module: "unicode",
- },
- Lint {
- name: "unimplemented",
- group: "restriction",
- desc: "`unimplemented!` should not be present in production code",
- deprecation: None,
- module: "panic_unimplemented",
- },
- Lint {
- name: "uninit_assumed_init",
- group: "correctness",
- desc: "`MaybeUninit::uninit().assume_init()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "unit_arg",
- group: "complexity",
- desc: "passing unit to a function",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "unit_cmp",
- group: "correctness",
- desc: "comparing unit values",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "unit_return_expecting_ord",
- group: "correctness",
- desc: "fn arguments of type Fn(...) -> Ord returning the unit type ().",
- deprecation: None,
- module: "unit_return_expecting_ord",
- },
- Lint {
- name: "unknown_clippy_lints",
- group: "style",
- desc: "unknown_lints for scoped Clippy lints",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "unnecessary_cast",
- group: "complexity",
- desc: "cast to the same type, e.g., `x as i32` where `x: i32`",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "unnecessary_filter_map",
- group: "complexity",
- desc: "using `filter_map` when a more succinct alternative exists",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "unnecessary_fold",
- group: "style",
- desc: "using `fold` when a more succinct alternative exists",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "unnecessary_lazy_evaluations",
- group: "style",
- desc: "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "unnecessary_mut_passed",
- group: "style",
- desc: "an argument passed as a mutable reference although the callee only demands an immutable reference",
- deprecation: None,
- module: "mut_reference",
- },
- Lint {
- name: "unnecessary_operation",
- group: "complexity",
- desc: "outer expressions with no effect",
- deprecation: None,
- module: "no_effect",
- },
- Lint {
- name: "unnecessary_sort_by",
- group: "complexity",
- desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer",
- deprecation: None,
- module: "unnecessary_sort_by",
- },
- Lint {
- name: "unnecessary_unwrap",
- group: "complexity",
- desc: "checks for calls of `unwrap[_err]()` that cannot fail",
- deprecation: None,
- module: "unwrap",
- },
- Lint {
- name: "unneeded_field_pattern",
- group: "restriction",
- desc: "struct fields bound to a wildcard instead of using `..`",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "unneeded_wildcard_pattern",
- group: "complexity",
- desc: "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "unnested_or_patterns",
- group: "pedantic",
- desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`",
- deprecation: None,
- module: "unnested_or_patterns",
- },
- Lint {
- name: "unreachable",
- group: "restriction",
- desc: "`unreachable!` should not be present in production code",
- deprecation: None,
- module: "panic_unimplemented",
- },
- Lint {
- name: "unreadable_literal",
- group: "pedantic",
- desc: "long integer literal without underscores",
- deprecation: None,
- module: "literal_representation",
- },
- Lint {
- name: "unsafe_derive_deserialize",
- group: "pedantic",
- desc: "deriving `serde::Deserialize` on a type that has methods using `unsafe`",
- deprecation: None,
- module: "derive",
- },
- Lint {
- name: "unsafe_removed_from_name",
- group: "style",
- desc: "`unsafe` removed from API names on import",
- deprecation: None,
- module: "unsafe_removed_from_name",
- },
- Lint {
- name: "unseparated_literal_suffix",
- group: "pedantic",
- desc: "literals whose suffix is not separated by an underscore",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "unsound_collection_transmute",
- group: "correctness",
- desc: "transmute between collections of layout-incompatible types",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "unused_io_amount",
- group: "correctness",
- desc: "unused written/read amount",
- deprecation: None,
- module: "unused_io_amount",
- },
- Lint {
- name: "unused_self",
- group: "pedantic",
- desc: "methods that contain a `self` argument but don\'t use it",
- deprecation: None,
- module: "unused_self",
- },
- Lint {
- name: "unused_unit",
- group: "style",
- desc: "needless unit expression",
- deprecation: None,
- module: "unused_unit",
- },
- Lint {
- name: "unusual_byte_groupings",
- group: "style",
- desc: "binary or hex literals that aren\'t grouped by four",
- deprecation: None,
- module: "literal_representation",
- },
- Lint {
- name: "unwrap_in_result",
- group: "restriction",
- desc: "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`",
- deprecation: None,
- module: "unwrap_in_result",
- },
- Lint {
- name: "unwrap_used",
- group: "restriction",
- desc: "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "use_debug",
- group: "restriction",
- desc: "use of `Debug`-based formatting",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "use_self",
- group: "nursery",
- desc: "unnecessary structure name repetition whereas `Self` is applicable",
- deprecation: None,
- module: "use_self",
- },
- Lint {
- name: "used_underscore_binding",
- group: "pedantic",
- desc: "using a binding which is prefixed with an underscore",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "useless_asref",
- group: "complexity",
- desc: "using `as_ref` where the types before and after the call are the same",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "useless_attribute",
- group: "correctness",
- desc: "use of lint attributes on `extern crate` items",
- deprecation: None,
- module: "attrs",
- },
- Lint {
- name: "useless_conversion",
- group: "complexity",
- desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type",
- deprecation: None,
- module: "useless_conversion",
- },
- Lint {
- name: "useless_format",
- group: "complexity",
- desc: "useless use of `format!`",
- deprecation: None,
- module: "format",
- },
- Lint {
- name: "useless_let_if_seq",
- group: "nursery",
- desc: "unidiomatic `let mut` declaration followed by initialization in `if`",
- deprecation: None,
- module: "let_if_seq",
- },
- Lint {
- name: "useless_transmute",
- group: "nursery",
- desc: "transmutes that have the same to and from types or could be a cast/coercion",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "useless_vec",
- group: "perf",
- desc: "useless `vec!`",
- deprecation: None,
- module: "vec",
- },
- Lint {
- name: "vec_box",
- group: "complexity",
- desc: "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap",
- deprecation: None,
- module: "types",
- },
- Lint {
- name: "vec_resize_to_zero",
- group: "correctness",
- desc: "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake",
- deprecation: None,
- module: "vec_resize_to_zero",
- },
- Lint {
- name: "verbose_bit_mask",
- group: "pedantic",
- desc: "expressions where a bit mask is less readable than the corresponding method call",
- deprecation: None,
- module: "bit_mask",
- },
- Lint {
- name: "verbose_file_reads",
- group: "restriction",
- desc: "use of `File::read_to_end` or `File::read_to_string`",
- deprecation: None,
- module: "verbose_file_reads",
- },
- Lint {
- name: "vtable_address_comparisons",
- group: "correctness",
- desc: "comparison with an address of a trait vtable",
- deprecation: None,
- module: "unnamed_address",
- },
- Lint {
- name: "while_immutable_condition",
- group: "correctness",
- desc: "variables used within while expression are not mutated in the body",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "while_let_loop",
- group: "complexity",
- desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "while_let_on_iterator",
- group: "style",
- desc: "using a while-let loop instead of a for loop on an iterator",
- deprecation: None,
- module: "loops",
- },
- Lint {
- name: "wildcard_dependencies",
- group: "cargo",
- desc: "wildcard dependencies being used",
- deprecation: None,
- module: "wildcard_dependencies",
- },
- Lint {
- name: "wildcard_enum_match_arm",
- group: "restriction",
- desc: "a wildcard enum match arm using `_`",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "wildcard_imports",
- group: "pedantic",
- desc: "lint `use _::*` statements",
- deprecation: None,
- module: "wildcard_imports",
- },
- Lint {
- name: "wildcard_in_or_patterns",
- group: "complexity",
- desc: "a wildcard pattern used with others patterns in same match arm",
- deprecation: None,
- module: "matches",
- },
- Lint {
- name: "write_literal",
- group: "style",
- desc: "writing a literal with a format string",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "write_with_newline",
- group: "style",
- desc: "using `write!()` with a format string that ends in a single newline",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "writeln_empty_string",
- group: "style",
- desc: "using `writeln!(buf, \"\")` with an empty string",
- deprecation: None,
- module: "write",
- },
- Lint {
- name: "wrong_pub_self_convention",
- group: "restriction",
- desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "wrong_self_convention",
- group: "style",
- desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention",
- deprecation: None,
- module: "methods",
- },
- Lint {
- name: "wrong_transmute",
- group: "correctness",
- desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless",
- deprecation: None,
- module: "transmute",
- },
- Lint {
- name: "zero_divided_by_zero",
- group: "complexity",
- desc: "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`",
- deprecation: None,
- module: "zero_div_zero",
- },
- Lint {
- name: "zero_prefixed_literal",
- group: "complexity",
- desc: "integer literals starting with `0`",
- deprecation: None,
- module: "misc_early",
- },
- Lint {
- name: "zero_ptr",
- group: "style",
- desc: "using `0 as *{const, mut} T`",
- deprecation: None,
- module: "misc",
- },
- Lint {
- name: "zst_offset",
- group: "correctness",
- desc: "Check for offset calculations on raw pointers to zero-sized types",
- deprecation: None,
- module: "methods",
- },
-]
-// end lint list, do not remove this comment, it’s used in `update_lints`
-});
+++ /dev/null
-#![warn(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)]
-#![allow(const_item_mutation)]
-
-use std::borrow::Cow;
-use std::cell::{Cell, UnsafeCell};
-use std::fmt::Display;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::sync::Once;
-
-const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-const CELL: Cell<usize> = Cell::new(6);
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
-const INTEGER: u8 = 8;
-const STRING: String = String::new();
-const STR: &str = "012345";
-const COW: Cow<str> = Cow::Borrowed("abcdef");
-const NO_ANN: &dyn Display = &70;
-static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
-const ONCE_INIT: Once = Once::new();
-
-trait Trait<T> {
- type AssocType;
-
- const ATOMIC: AtomicUsize;
- const INPUT: T;
- const ASSOC: Self::AssocType;
-
- fn function() {
- let _ = &Self::INPUT;
- let _ = &Self::ASSOC;
- }
-}
-
-impl Trait<u32> for u64 {
- type AssocType = AtomicUsize;
-
- const ATOMIC: AtomicUsize = AtomicUsize::new(9);
- const INPUT: u32 = 10;
- const ASSOC: Self::AssocType = AtomicUsize::new(11);
-
- fn function() {
- let _ = &Self::INPUT;
- let _ = &Self::ASSOC; //~ ERROR interior mutability
- }
-}
-
-// This is just a pointer that can be safely dereferended,
-// it's semantically the same as `&'static T`;
-// but it isn't allowed to make a static reference from an arbitrary integer value at the moment.
-// For more information, please see the issue #5918.
-pub struct StaticRef<T> {
- ptr: *const T,
-}
-
-impl<T> StaticRef<T> {
- /// Create a new `StaticRef` from a raw pointer
- ///
- /// ## Safety
- ///
- /// Callers must pass in a reference to statically allocated memory which
- /// does not overlap with other values.
- pub const unsafe fn new(ptr: *const T) -> StaticRef<T> {
- StaticRef { ptr }
- }
-}
-
-impl<T> std::ops::Deref for StaticRef<T> {
- type Target = T;
-
- fn deref(&self) -> &'static T {
- unsafe { &*self.ptr }
- }
-}
-
-// use a tuple to make sure referencing a field behind a pointer isn't linted.
-const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
-
-fn main() {
- ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
- assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
-
- let _once = ONCE_INIT;
- let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
- let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
- let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
- let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
- let _atomic_into_inner = ATOMIC.into_inner();
- // these should be all fine.
- let _twice = (ONCE_INIT, ONCE_INIT);
- let _ref_twice = &(ONCE_INIT, ONCE_INIT);
- let _ref_once = &(ONCE_INIT, ONCE_INIT).0;
- let _array_twice = [ONCE_INIT, ONCE_INIT];
- let _ref_array_twice = &[ONCE_INIT, ONCE_INIT];
- let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0];
-
- // referencing projection is still bad.
- let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
- let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
- let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
- let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
- let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
- let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability
- let _ = &ATOMIC_TUPLE.2;
- let _ = (&&&&ATOMIC_TUPLE).0;
- let _ = (&&&&ATOMIC_TUPLE).2;
- let _ = ATOMIC_TUPLE.0;
- let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
- let _ = ATOMIC_TUPLE.1.into_iter();
- let _ = ATOMIC_TUPLE.2;
- let _ = &{ ATOMIC_TUPLE };
-
- CELL.set(2); //~ ERROR interior mutability
- assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
-
- assert_eq!(INTEGER, 8);
- assert!(STRING.is_empty());
-
- let a = ATOMIC;
- a.store(4, Ordering::SeqCst);
- assert_eq!(a.load(Ordering::SeqCst), 4);
-
- STATIC_TUPLE.0.store(3, Ordering::SeqCst);
- assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3);
- assert!(STATIC_TUPLE.1.is_empty());
-
- u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
- assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
-
- assert_eq!(NO_ANN.to_string(), "70"); // should never lint this.
-
- let _ = &CELL_REF.0;
-}
+++ /dev/null
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:44:18
- |
-LL | let _ = &Self::ASSOC; //~ ERROR interior mutability
- | ^^^^^^^^^^^
- |
- = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:80:5
- |
-LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
- | ^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:81:16
- |
-LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
- | ^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:84:22
- |
-LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
- | ^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:85:25
- |
-LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
- | ^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:86:27
- |
-LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
- | ^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:87:26
- |
-LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
- | ^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:98:14
- |
-LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
- | ^^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:99:14
- |
-LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
- | ^^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:100:19
- |
-LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
- | ^^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:101:14
- |
-LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
- | ^^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:102:13
- |
-LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
- | ^^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:108:13
- |
-LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
- | ^^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:113:5
- |
-LL | CELL.set(2); //~ ERROR interior mutability
- | ^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:114:16
- |
-LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
- | ^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:127:5
- |
-LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
- | ^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
- --> $DIR/borrow_interior_mutable_const.rs:128:16
- |
-LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
- | ^^^^^^^^^^^
- |
- = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 17 previous errors
-
--- /dev/null
+// this file solely exists to test constants defined in foreign crates.
+// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure.
+
+#![allow(clippy::declare_interior_mutable_const)]
+
+use std::sync::atomic::AtomicUsize;
+
+enum Private<T> {
+ ToBeUnfrozen(T),
+ Frozen(usize),
+}
+
+pub struct Wrapper(Private<AtomicUsize>);
+
+pub const WRAPPED_PRIVATE_UNFROZEN_VARIANT: Wrapper = Wrapper(Private::ToBeUnfrozen(AtomicUsize::new(6)));
+pub const WRAPPED_PRIVATE_FROZEN_VARIANT: Wrapper = Wrapper(Private::Frozen(7));
--- /dev/null
+// aux-build:helper.rs
+
+#![warn(clippy::borrow_interior_mutable_const)]
+#![allow(clippy::declare_interior_mutable_const)]
+
+// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions.
+
+extern crate helper;
+
+use std::cell::Cell;
+use std::sync::atomic::AtomicUsize;
+
+enum OptionalCell {
+ Unfrozen(Cell<bool>),
+ Frozen,
+}
+
+const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
+const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+fn borrow_optional_cell() {
+ let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability
+ let _ = &FROZEN_VARIANT;
+}
+
+trait AssocConsts {
+ const TO_BE_UNFROZEN_VARIANT: OptionalCell;
+ const TO_BE_FROZEN_VARIANT: OptionalCell;
+
+ const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+ const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+ fn function() {
+ // This is the "suboptimal behavior" mentioned in `is_value_unfrozen`
+ // caused by a similar reason to unfrozen types without any default values
+ // get linted even if it has frozen variants'.
+ let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable
+
+ // The lint ignores default values because an impl of this trait can set
+ // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`.
+ let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable
+ }
+}
+
+impl AssocConsts for u64 {
+ const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+ const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+ fn function() {
+ let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
+ let _ = &<Self as AssocConsts>::TO_BE_FROZEN_VARIANT;
+ let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable
+ let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
+ }
+}
+
+trait AssocTypes {
+ type ToBeUnfrozen;
+
+ const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
+ const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
+
+ // there's no need to test here because it's the exactly same as `trait::AssocTypes`
+ fn function();
+}
+
+impl AssocTypes for u64 {
+ type ToBeUnfrozen = AtomicUsize;
+
+ const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
+ const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
+
+ fn function() {
+ let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
+ let _ = &<Self as AssocTypes>::TO_BE_FROZEN_VARIANT;
+ }
+}
+
+enum BothOfCellAndGeneric<T> {
+ Unfrozen(Cell<*const T>),
+ Generic(*const T),
+ Frozen(usize),
+}
+
+impl<T> BothOfCellAndGeneric<T> {
+ const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
+ const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
+ const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
+
+ fn function() {
+ let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability
+ let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability
+ let _ = &Self::FROZEN_VARIANT;
+ }
+}
+
+fn main() {
+ // constants defined in foreign crates
+ let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability
+ let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT;
+}
--- /dev/null
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:22:14
+ |
+LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:37:18
+ |
+LL | let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:41:18
+ |
+LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:50:18
+ |
+LL | let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:52:18
+ |
+LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:74:18
+ |
+LL | let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:91:18
+ |
+LL | let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:92:18
+ |
+LL | let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/enums.rs:99:14
+ |
+LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: aborting due to 9 previous errors
+
--- /dev/null
+#![warn(clippy::borrow_interior_mutable_const)]
+#![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)]
+#![allow(const_item_mutation)]
+
+use std::borrow::Cow;
+use std::cell::{Cell, UnsafeCell};
+use std::fmt::Display;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Once;
+
+const ATOMIC: AtomicUsize = AtomicUsize::new(5);
+const CELL: Cell<usize> = Cell::new(6);
+const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+const INTEGER: u8 = 8;
+const STRING: String = String::new();
+const STR: &str = "012345";
+const COW: Cow<str> = Cow::Borrowed("abcdef");
+const NO_ANN: &dyn Display = &70;
+static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
+const ONCE_INIT: Once = Once::new();
+
+// This is just a pointer that can be safely dereferenced,
+// it's semantically the same as `&'static T`;
+// but it isn't allowed to make a static reference from an arbitrary integer value at the moment.
+// For more information, please see the issue #5918.
+pub struct StaticRef<T> {
+ ptr: *const T,
+}
+
+impl<T> StaticRef<T> {
+ /// Create a new `StaticRef` from a raw pointer
+ ///
+ /// ## Safety
+ ///
+ /// Callers must pass in a reference to statically allocated memory which
+ /// does not overlap with other values.
+ pub const unsafe fn new(ptr: *const T) -> StaticRef<T> {
+ StaticRef { ptr }
+ }
+}
+
+impl<T> std::ops::Deref for StaticRef<T> {
+ type Target = T;
+
+ fn deref(&self) -> &'static T {
+ unsafe { &*self.ptr }
+ }
+}
+
+// use a tuple to make sure referencing a field behind a pointer isn't linted.
+const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
+
+fn main() {
+ ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
+ assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
+
+ let _once = ONCE_INIT;
+ let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
+ let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
+ let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
+ let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
+ let _atomic_into_inner = ATOMIC.into_inner();
+ // these should be all fine.
+ let _twice = (ONCE_INIT, ONCE_INIT);
+ let _ref_twice = &(ONCE_INIT, ONCE_INIT);
+ let _ref_once = &(ONCE_INIT, ONCE_INIT).0;
+ let _array_twice = [ONCE_INIT, ONCE_INIT];
+ let _ref_array_twice = &[ONCE_INIT, ONCE_INIT];
+ let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0];
+
+ // referencing projection is still bad.
+ let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
+ let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
+ let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
+ let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+ let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
+ let _ = &*ATOMIC_TUPLE.1;
+ let _ = &ATOMIC_TUPLE.2;
+ let _ = (&&&&ATOMIC_TUPLE).0;
+ let _ = (&&&&ATOMIC_TUPLE).2;
+ let _ = ATOMIC_TUPLE.0;
+ let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+ let _ = ATOMIC_TUPLE.1.into_iter();
+ let _ = ATOMIC_TUPLE.2;
+ let _ = &{ ATOMIC_TUPLE };
+
+ CELL.set(2); //~ ERROR interior mutability
+ assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
+
+ assert_eq!(INTEGER, 8);
+ assert!(STRING.is_empty());
+
+ let a = ATOMIC;
+ a.store(4, Ordering::SeqCst);
+ assert_eq!(a.load(Ordering::SeqCst), 4);
+
+ STATIC_TUPLE.0.store(3, Ordering::SeqCst);
+ assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3);
+ assert!(STATIC_TUPLE.1.is_empty());
+
+ assert_eq!(NO_ANN.to_string(), "70"); // should never lint this.
+
+ let _ = &CELL_REF.0;
+}
--- /dev/null
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:54:5
+ |
+LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
+ | ^^^^^^
+ |
+ = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:55:16
+ |
+LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
+ | ^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:58:22
+ |
+LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
+ | ^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:59:25
+ |
+LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
+ | ^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:60:27
+ |
+LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
+ | ^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:61:26
+ |
+LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
+ | ^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:72:14
+ |
+LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:73:14
+ |
+LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:74:19
+ |
+LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:75:14
+ |
+LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:76:13
+ |
+LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:82:13
+ |
+LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:87:5
+ |
+LL | CELL.set(2); //~ ERROR interior mutability
+ | ^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/others.rs:88:16
+ |
+LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
+ | ^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: aborting due to 14 previous errors
+
--- /dev/null
+#![warn(clippy::borrow_interior_mutable_const)]
+#![allow(clippy::declare_interior_mutable_const)]
+
+// this file replicates its `declare` counterpart. Please see it for more discussions.
+
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+trait ConcreteTypes {
+ const ATOMIC: AtomicUsize;
+ const STRING: String;
+
+ fn function() {
+ let _ = &Self::ATOMIC; //~ ERROR interior mutable
+ let _ = &Self::STRING;
+ }
+}
+
+impl ConcreteTypes for u64 {
+ const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+ const STRING: String = String::new();
+
+ fn function() {
+ // Lint this again since implementers can choose not to borrow it.
+ let _ = &Self::ATOMIC; //~ ERROR interior mutable
+ let _ = &Self::STRING;
+ }
+}
+
+// a helper trait used below
+trait ConstDefault {
+ const DEFAULT: Self;
+}
+
+trait GenericTypes<T, U> {
+ const TO_REMAIN_GENERIC: T;
+ const TO_BE_CONCRETE: U;
+
+ fn function() {
+ let _ = &Self::TO_REMAIN_GENERIC;
+ }
+}
+
+impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for Vec<T> {
+ const TO_REMAIN_GENERIC: T = T::DEFAULT;
+ const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
+
+ fn function() {
+ let _ = &Self::TO_REMAIN_GENERIC;
+ let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable
+ }
+}
+
+// a helper type used below
+pub struct Wrapper<T>(T);
+
+trait AssocTypes {
+ type ToBeFrozen;
+ type ToBeUnfrozen;
+ type ToBeGenericParam;
+
+ const TO_BE_FROZEN: Self::ToBeFrozen;
+ const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
+ const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
+ const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
+
+ fn function() {
+ let _ = &Self::TO_BE_FROZEN;
+ let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
+ }
+}
+
+impl<T: ConstDefault> AssocTypes for Vec<T> {
+ type ToBeFrozen = u16;
+ type ToBeUnfrozen = AtomicUsize;
+ type ToBeGenericParam = T;
+
+ const TO_BE_FROZEN: Self::ToBeFrozen = 12;
+ const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
+ const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
+ const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
+
+ fn function() {
+ let _ = &Self::TO_BE_FROZEN;
+ let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable
+ let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable
+ let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM;
+ }
+}
+
+// a helper trait used below
+trait AssocTypesHelper {
+ type NotToBeBounded;
+ type ToBeBounded;
+
+ const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
+}
+
+trait AssocTypesFromGenericParam<T>
+where
+ T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ const NOT_BOUNDED: T::NotToBeBounded;
+ const BOUNDED: T::ToBeBounded;
+
+ fn function() {
+ let _ = &Self::NOT_BOUNDED;
+ let _ = &Self::BOUNDED; //~ ERROR interior mutable
+ }
+}
+
+impl<T> AssocTypesFromGenericParam<T> for Vec<T>
+where
+ T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+ const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
+
+ fn function() {
+ let _ = &Self::NOT_BOUNDED;
+ let _ = &Self::BOUNDED; //~ ERROR interior mutable
+ }
+}
+
+trait SelfType: Sized {
+ const SELF: Self;
+ const WRAPPED_SELF: Option<Self>;
+
+ fn function() {
+ let _ = &Self::SELF;
+ let _ = &Self::WRAPPED_SELF;
+ }
+}
+
+impl SelfType for u64 {
+ const SELF: Self = 16;
+ const WRAPPED_SELF: Option<Self> = Some(20);
+
+ fn function() {
+ let _ = &Self::SELF;
+ let _ = &Self::WRAPPED_SELF;
+ }
+}
+
+impl SelfType for AtomicUsize {
+ const SELF: Self = AtomicUsize::new(17);
+ const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
+
+ fn function() {
+ let _ = &Self::SELF; //~ ERROR interior mutable
+ let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable
+ }
+}
+
+trait BothOfCellAndGeneric<T> {
+ const DIRECT: Cell<T>;
+ const INDIRECT: Cell<*const T>;
+
+ fn function() {
+ let _ = &Self::DIRECT;
+ let _ = &Self::INDIRECT; //~ ERROR interior mutable
+ }
+}
+
+impl<T: ConstDefault> BothOfCellAndGeneric<T> for Vec<T> {
+ const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
+ const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
+
+ fn function() {
+ let _ = &Self::DIRECT;
+ let _ = &Self::INDIRECT; //~ ERROR interior mutable
+ }
+}
+
+struct Local<T>(T);
+
+impl<T> Local<T>
+where
+ T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ const ATOMIC: AtomicUsize = AtomicUsize::new(18);
+ const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
+
+ const GENERIC_TYPE: T = T::DEFAULT;
+
+ const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+ const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
+
+ fn function() {
+ let _ = &Self::ATOMIC; //~ ERROR interior mutable
+ let _ = &Self::COW;
+ let _ = &Self::GENERIC_TYPE;
+ let _ = &Self::ASSOC_TYPE;
+ let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable
+ }
+}
+
+fn main() {
+ u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
+ assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
+}
--- /dev/null
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:15:18
+ |
+LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^
+ |
+ = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:26:18
+ |
+LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:51:18
+ |
+LL | let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:86:18
+ |
+LL | let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:87:18
+ |
+LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:109:18
+ |
+LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:122:18
+ |
+LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:151:18
+ |
+LL | let _ = &Self::SELF; //~ ERROR interior mutable
+ | ^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:152:18
+ |
+LL | let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:162:18
+ |
+LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:172:18
+ |
+LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:191:18
+ |
+LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:195:18
+ |
+LL | let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:200:5
+ |
+LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
+ | ^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+ --> $DIR/traits.rs:201:16
+ |
+LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
+ | ^^^^^^^^^^^
+ |
+ = help: assign this const to a local or static variable, and use the variable here
+
+error: aborting due to 15 previous errors
+
| ^^^^^^^
|
= note: `-D clippy::empty-loop` implied by `-D warnings`
- = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+ = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
error: aborting due to 2 previous errors
--- /dev/null
+fn cmark_check() {
+ let mut link_err = false;
+ macro_rules! cmark_error {
+ ($bad:expr) => {
+ *$bad = true;
+ };
+ }
+ cmark_error!(&mut link_err);
+}
+
+pub fn main() {}
--- /dev/null
+#[allow(clippy::needless_borrowed_reference)]
+fn main() {
+ let mut v = Vec::<String>::new();
+ let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+}
+++ /dev/null
-#![warn(clippy::declare_interior_mutable_const)]
-
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::fmt::Display;
-use std::sync::atomic::AtomicUsize;
-use std::sync::Once;
-
-const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
-const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
-//~^ ERROR interior mutable
-
-macro_rules! declare_const {
- ($name:ident: $ty:ty = $e:expr) => {
- const $name: $ty = $e;
- };
-}
-declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
-
-// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
-
-const INTEGER: u8 = 8;
-const STRING: String = String::new();
-const STR: &str = "012345";
-const COW: Cow<str> = Cow::Borrowed("abcdef");
-//^ note: a const item of Cow is used in the `postgres` package.
-
-const NO_ANN: &dyn Display = &70;
-
-static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
-//^ there should be no lints on this line
-
-#[allow(clippy::declare_interior_mutable_const)]
-const ONCE_INIT: Once = Once::new();
-
-// a constant whose type is a concrete type should be linted at the definition site.
-trait ConcreteTypes {
- const ATOMIC: AtomicUsize; //~ ERROR interior mutable
- const INTEGER: u64;
- const STRING: String;
- declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
-}
-
-impl ConcreteTypes for u64 {
- const ATOMIC: AtomicUsize = AtomicUsize::new(9);
- const INTEGER: u64 = 10;
- const STRING: String = String::new();
-}
-
-// a helper trait used below
-trait ConstDefault {
- const DEFAULT: Self;
-}
-
-// a constant whose type is a generic type should be linted at the implementation site.
-trait GenericTypes<T, U> {
- const TO_REMAIN_GENERIC: T;
- const TO_BE_CONCRETE: U;
-
- const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC;
- declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC);
-}
-
-impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for u64 {
- const TO_REMAIN_GENERIC: T = T::DEFAULT;
- const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
-}
-
-// a helper type used below
-struct Wrapper<T>(T);
-
-// a constant whose type is an associated type should be linted at the implementation site, too.
-trait AssocTypes {
- type ToBeFrozen;
- type ToBeUnfrozen;
- type ToBeGenericParam;
-
- const TO_BE_FROZEN: Self::ToBeFrozen;
- const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
- const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
- // to ensure it can handle things when a generic type remains after normalization.
- const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
-}
-
-impl<T: ConstDefault> AssocTypes for Vec<T> {
- type ToBeFrozen = u16;
- type ToBeUnfrozen = AtomicUsize;
- type ToBeGenericParam = T;
-
- const TO_BE_FROZEN: Self::ToBeFrozen = 12;
- const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
- const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
- const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
-}
-
-// a helper trait used below
-trait AssocTypesHelper {
- type NotToBeBounded;
- type ToBeBounded;
-
- const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
-}
-
-// a constant whose type is an assoc type originated from a generic param bounded at the definition
-// site should be linted at there.
-trait AssocTypesFromGenericParam<T>
-where
- T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
- const NOT_BOUNDED: T::NotToBeBounded;
- const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
-}
-
-impl<T> AssocTypesFromGenericParam<T> for u64
-where
- T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
- // an associated type could remain unknown in a trait impl.
- const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
- const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
-}
-
-// a constant whose type is `Self` should be linted at the implementation site as well.
-// (`Option` requires `Sized` bound.)
-trait SelfType: Sized {
- const SELF: Self;
- // this was the one in the original issue (#5050).
- const WRAPPED_SELF: Option<Self>;
-}
-
-impl SelfType for u64 {
- const SELF: Self = 16;
- const WRAPPED_SELF: Option<Self> = Some(20);
-}
-
-impl SelfType for AtomicUsize {
- // this (interior mutable `Self` const) exists in `parking_lot`.
- // `const_trait_impl` will replace it in the future, hopefully.
- const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
- const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
-}
-
-// Even though a constant contains a generic type, if it also have a interior mutable type,
-// it should be linted at the definition site.
-trait BothOfCellAndGeneric<T> {
- // this is a false negative in the current implementation.
- const DIRECT: Cell<T>;
- const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
-}
-
-impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
- const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
- const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
-}
-
-struct Local<T>(T);
-
-// a constant in an inherent impl are essentially the same as a normal const item
-// except there can be a generic or associated type.
-impl<T> Local<T>
-where
- T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
- const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
- const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
-
- const GENERIC_TYPE: T = T::DEFAULT;
-
- const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
- const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
-}
-
-fn main() {}
+++ /dev/null
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:9:1
- |
-LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
- | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | make this a static item (maybe with lazy_static)
- |
- = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:10:1
- |
-LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
- | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | make this a static item (maybe with lazy_static)
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:11:1
- |
-LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
- | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | make this a static item (maybe with lazy_static)
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:16:9
- |
-LL | const $name: $ty = $e;
- | ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
- | ------------------------------------------ in this macro invocation
- |
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:39:5
- |
-LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:16:9
- |
-LL | const $name: $ty = $e;
- | ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
- | ----------------------------------------------------------- in this macro invocation
- |
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:67:5
- |
-LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:92:5
- |
-LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:93:5
- |
-LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:112:5
- |
-LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:140:5
- |
-LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:141:5
- |
-LL | const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:149:5
- |
-LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:165:5
- |
-LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should never be interior mutable
- --> $DIR/declare_interior_mutable_const.rs:171:5
- |
-LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 15 previous errors
-
--- /dev/null
+#![warn(clippy::declare_interior_mutable_const)]
+
+use std::cell::Cell;
+use std::sync::atomic::AtomicUsize;
+
+enum OptionalCell {
+ Unfrozen(Cell<bool>),
+ Frozen,
+}
+
+// a constant with enums should be linted only when the used variant is unfrozen (#3962).
+const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable
+const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+const fn unfrozen_variant() -> OptionalCell {
+ OptionalCell::Unfrozen(Cell::new(false))
+}
+
+const fn frozen_variant() -> OptionalCell {
+ OptionalCell::Frozen
+}
+
+const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable
+const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
+
+enum NestedInnermost {
+ Unfrozen(AtomicUsize),
+ Frozen,
+}
+
+struct NestedInner {
+ inner: NestedInnermost,
+}
+
+enum NestedOuter {
+ NestedInner(NestedInner),
+ NotNested(usize),
+}
+
+struct NestedOutermost {
+ outer: NestedOuter,
+}
+
+// a constant with enums should be linted according to its value, no matter how structs involve.
+const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
+ outer: NestedOuter::NestedInner(NestedInner {
+ inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
+ }),
+}; //~ ERROR interior mutable
+const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost {
+ outer: NestedOuter::NestedInner(NestedInner {
+ inner: NestedInnermost::Frozen,
+ }),
+};
+
+trait AssocConsts {
+ // When there's no default value, lint it only according to its type.
+ // Further details are on the corresponding code (`NonCopyConst::check_trait_item`).
+ const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
+ const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
+
+ // Lint default values accordingly.
+ const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable
+ const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+}
+
+// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it
+// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'.
+impl AssocConsts for u64 {
+ const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+ const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+ // even if this sets an unfrozen variant, the lint ignores it.
+ const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+}
+
+// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters
+// here are values; and I think substituted generics at definitions won't appear in MIR.
+trait AssocTypes {
+ type ToBeUnfrozen;
+
+ const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
+ const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
+}
+
+impl AssocTypes for u64 {
+ type ToBeUnfrozen = AtomicUsize;
+
+ const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
+ const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
+}
+
+// Use raw pointers since direct generics have a false negative at the type level.
+enum BothOfCellAndGeneric<T> {
+ Unfrozen(Cell<*const T>),
+ Generic(*const T),
+ Frozen(usize),
+}
+
+impl<T> BothOfCellAndGeneric<T> {
+ const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
+
+ // This is a false positive. The argument about this is on `is_value_unfrozen_raw`
+ const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
+
+ const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
+
+ // This is what is likely to be a false negative when one tries to fix
+ // the `GENERIC_VARIANT` false positive.
+ const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable
+}
+
+// associated types here is basically the same as the one above.
+trait BothOfCellAndGenericWithAssocType {
+ type AssocType;
+
+ const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
+ BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
+ const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
+ const FROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Frozen(5);
+}
+
+fn main() {}
--- /dev/null
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:12:1
+ |
+LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable
+ | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | make this a static item (maybe with lazy_static)
+ |
+ = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:23:1
+ |
+LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable
+ | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | make this a static item (maybe with lazy_static)
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:45:1
+ |
+LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
+ | ^----
+ | |
+ | _make this a static item (maybe with lazy_static)
+ | |
+LL | | outer: NestedOuter::NestedInner(NestedInner {
+LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
+LL | | }),
+LL | | }; //~ ERROR interior mutable
+ | |__^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:59:5
+ |
+LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:60:5
+ |
+LL | const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:63:5
+ |
+LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:89:5
+ |
+LL | const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:101:5
+ |
+LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mut...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:104:5
+ |
+LL | const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:110:5
+ |
+LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:117:5
+ |
+LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
+LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
+ | |____________________________________________________________________^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/enums.rs:119:5
+ |
+LL | const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mu...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
--- /dev/null
+#![warn(clippy::declare_interior_mutable_const)]
+
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::fmt::Display;
+use std::sync::atomic::AtomicUsize;
+use std::sync::Once;
+
+const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
+const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
+const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+//~^ ERROR interior mutable
+
+macro_rules! declare_const {
+ ($name:ident: $ty:ty = $e:expr) => {
+ const $name: $ty = $e;
+ };
+}
+declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
+
+// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
+
+const INTEGER: u8 = 8;
+const STRING: String = String::new();
+const STR: &str = "012345";
+const COW: Cow<str> = Cow::Borrowed("abcdef");
+//^ note: a const item of Cow is used in the `postgres` package.
+
+const NO_ANN: &dyn Display = &70;
+
+static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
+//^ there should be no lints on this line
+
+fn main() {}
--- /dev/null
+error: a `const` item should never be interior mutable
+ --> $DIR/others.rs:9:1
+ |
+LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
+ | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | make this a static item (maybe with lazy_static)
+ |
+ = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
+
+error: a `const` item should never be interior mutable
+ --> $DIR/others.rs:10:1
+ |
+LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
+ | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | make this a static item (maybe with lazy_static)
+
+error: a `const` item should never be interior mutable
+ --> $DIR/others.rs:11:1
+ |
+LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+ | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | make this a static item (maybe with lazy_static)
+
+error: a `const` item should never be interior mutable
+ --> $DIR/others.rs:16:9
+ |
+LL | const $name: $ty = $e;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
+ | ------------------------------------------ in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+#![warn(clippy::declare_interior_mutable_const)]
+
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::sync::atomic::AtomicUsize;
+
+macro_rules! declare_const {
+ ($name:ident: $ty:ty = $e:expr) => {
+ const $name: $ty = $e;
+ };
+}
+
+// a constant whose type is a concrete type should be linted at the definition site.
+trait ConcreteTypes {
+ const ATOMIC: AtomicUsize; //~ ERROR interior mutable
+ const INTEGER: u64;
+ const STRING: String;
+ declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
+}
+
+impl ConcreteTypes for u64 {
+ const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+ const INTEGER: u64 = 10;
+ const STRING: String = String::new();
+}
+
+// a helper trait used below
+trait ConstDefault {
+ const DEFAULT: Self;
+}
+
+// a constant whose type is a generic type should be linted at the implementation site.
+trait GenericTypes<T, U> {
+ const TO_REMAIN_GENERIC: T;
+ const TO_BE_CONCRETE: U;
+
+ const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC;
+ declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC);
+}
+
+impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for u64 {
+ const TO_REMAIN_GENERIC: T = T::DEFAULT;
+ const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
+}
+
+// a helper type used below
+struct Wrapper<T>(T);
+
+// a constant whose type is an associated type should be linted at the implementation site, too.
+trait AssocTypes {
+ type ToBeFrozen;
+ type ToBeUnfrozen;
+ type ToBeGenericParam;
+
+ const TO_BE_FROZEN: Self::ToBeFrozen;
+ const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
+ const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
+ // to ensure it can handle things when a generic type remains after normalization.
+ const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
+}
+
+impl<T: ConstDefault> AssocTypes for Vec<T> {
+ type ToBeFrozen = u16;
+ type ToBeUnfrozen = AtomicUsize;
+ type ToBeGenericParam = T;
+
+ const TO_BE_FROZEN: Self::ToBeFrozen = 12;
+ const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
+ const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
+ const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
+}
+
+// a helper trait used below
+trait AssocTypesHelper {
+ type NotToBeBounded;
+ type ToBeBounded;
+
+ const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
+}
+
+// a constant whose type is an assoc type originated from a generic param bounded at the definition
+// site should be linted at there.
+trait AssocTypesFromGenericParam<T>
+where
+ T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ const NOT_BOUNDED: T::NotToBeBounded;
+ const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
+}
+
+impl<T> AssocTypesFromGenericParam<T> for u64
+where
+ T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ // an associated type could remain unknown in a trait impl.
+ const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+ const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
+}
+
+// a constant whose type is `Self` should be linted at the implementation site as well.
+// (`Option` requires `Sized` bound.)
+trait SelfType: Sized {
+ const SELF: Self;
+ // this was the one in the original issue (#5050).
+ const WRAPPED_SELF: Option<Self>;
+}
+
+impl SelfType for u64 {
+ const SELF: Self = 16;
+ const WRAPPED_SELF: Option<Self> = Some(20);
+}
+
+impl SelfType for AtomicUsize {
+ // this (interior mutable `Self` const) exists in `parking_lot`.
+ // `const_trait_impl` will replace it in the future, hopefully.
+ const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
+ const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
+}
+
+// Even though a constant contains a generic type, if it also have a interior mutable type,
+// it should be linted at the definition site.
+trait BothOfCellAndGeneric<T> {
+ // this is a false negative in the current implementation.
+ const DIRECT: Cell<T>;
+ const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
+}
+
+impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
+ const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
+ const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
+}
+
+struct Local<T>(T);
+
+// a constant in an inherent impl are essentially the same as a normal const item
+// except there can be a generic or associated type.
+impl<T> Local<T>
+where
+ T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+ const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
+ const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
+
+ const GENERIC_TYPE: T = T::DEFAULT;
+
+ const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+ const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
+}
+
+fn main() {}
--- /dev/null
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:15:5
+ |
+LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:9:9
+ |
+LL | const $name: $ty = $e;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
+ | ----------------------------------------------------------- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:43:5
+ |
+LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:68:5
+ |
+LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:69:5
+ |
+LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:88:5
+ |
+LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:116:5
+ |
+LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:117:5
+ |
+LL | const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:125:5
+ |
+LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:141:5
+ |
+LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+ --> $DIR/traits.rs:147:5
+ |
+LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
#[warn(clippy::regex_macro)]
#[warn(clippy::drop_bounds)]
#[warn(clippy::temporary_cstring_as_ptr)]
+#[warn(clippy::panic_params)]
fn main() {}
LL | #[warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt``
+ --> $DIR/deprecated.rs:13:8
+ |
+LL | #[warn(clippy::panic_params)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
--> $DIR/deprecated.rs:1:8
|
LL | #[warn(clippy::str_to_string)]
| ^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
// run-rustfix
+#![warn(clippy::deref_addrof)]
fn get_number() -> usize {
10
#[allow(clippy::many_single_char_names, clippy::double_parens)]
#[allow(unused_variables, unused_parens)]
-#[warn(clippy::deref_addrof)]
fn main() {
let a = 10;
let aref = &a;
let b = *aref;
}
+
+#[rustfmt::skip]
+macro_rules! m {
+ ($visitor: expr) => {
+ $visitor
+ };
+}
+
+#[rustfmt::skip]
+macro_rules! m_mut {
+ ($visitor: expr) => {
+ $visitor
+ };
+}
+
+pub struct S;
+impl S {
+ pub fn f(&self) -> &Self {
+ m!(self)
+ }
+ pub fn f_mut(&self) -> &Self {
+ m_mut!(self)
+ }
+}
// run-rustfix
+#![warn(clippy::deref_addrof)]
fn get_number() -> usize {
10
#[allow(clippy::many_single_char_names, clippy::double_parens)]
#[allow(unused_variables, unused_parens)]
-#[warn(clippy::deref_addrof)]
fn main() {
let a = 10;
let aref = &a;
let b = **&aref;
}
+
+#[rustfmt::skip]
+macro_rules! m {
+ ($visitor: expr) => {
+ *& $visitor
+ };
+}
+
+#[rustfmt::skip]
+macro_rules! m_mut {
+ ($visitor: expr) => {
+ *& mut $visitor
+ };
+}
+
+pub struct S;
+impl S {
+ pub fn f(&self) -> &Self {
+ m!(self)
+ }
+ pub fn f_mut(&self) -> &Self {
+ m_mut!(self)
+ }
+}
LL | let b = **&aref;
| ^^^^^^ help: try this: `aref`
-error: aborting due to 8 previous errors
+error: immediately dereferencing a reference
+ --> $DIR/deref_addrof.rs:44:9
+ |
+LL | *& $visitor
+ | ^^^^^^^^^^^ help: try this: `$visitor`
+...
+LL | m!(self)
+ | -------- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: immediately dereferencing a reference
+ --> $DIR/deref_addrof.rs:51:9
+ |
+LL | *& mut $visitor
+ | ^^^^^^^^^^^^^^^ help: try this: `$visitor`
+...
+LL | m_mut!(self)
+ | ------------ in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 10 previous errors
#![warn(clippy::derive_ord_xor_partial_ord)]
+#![allow(clippy::unnecessary_wraps)]
use std::cmp::Ordering;
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
- --> $DIR/derive_ord_xor_partial_ord.rs:20:10
+ --> $DIR/derive_ord_xor_partial_ord.rs:21:10
|
LL | #[derive(Ord, PartialEq, Eq)]
| ^^^
|
= note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings`
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:23:1
+ --> $DIR/derive_ord_xor_partial_ord.rs:24:1
|
LL | / impl PartialOrd for DeriveOrd {
LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
- --> $DIR/derive_ord_xor_partial_ord.rs:29:10
+ --> $DIR/derive_ord_xor_partial_ord.rs:30:10
|
LL | #[derive(Ord, PartialEq, Eq)]
| ^^^
|
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:32:1
+ --> $DIR/derive_ord_xor_partial_ord.rs:33:1
|
LL | / impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable {
LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Ord` explicitly but have derived `PartialOrd`
- --> $DIR/derive_ord_xor_partial_ord.rs:41:1
+ --> $DIR/derive_ord_xor_partial_ord.rs:42:1
|
LL | / impl std::cmp::Ord for DerivePartialOrd {
LL | | fn cmp(&self, other: &Self) -> Ordering {
| |_^
|
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:38:10
+ --> $DIR/derive_ord_xor_partial_ord.rs:39:10
|
LL | #[derive(PartialOrd, PartialEq, Eq)]
| ^^^^^^^^^^
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Ord` explicitly but have derived `PartialOrd`
- --> $DIR/derive_ord_xor_partial_ord.rs:61:5
+ --> $DIR/derive_ord_xor_partial_ord.rs:62:5
|
LL | / impl Ord for DerivePartialOrdInUseOrd {
LL | | fn cmp(&self, other: &Self) -> Ordering {
| |_____^
|
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:58:14
+ --> $DIR/derive_ord_xor_partial_ord.rs:59:14
|
LL | #[derive(PartialOrd, PartialEq, Eq)]
| ^^^^^^^^^^
// edition:2018
#![warn(clippy::missing_errors_doc)]
#![allow(clippy::result_unit_err)]
+#![allow(clippy::unnecessary_wraps)]
use std::io;
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:7:1
+ --> $DIR/doc_errors.rs:8:1
|
LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
= note: `-D clippy::missing-errors-doc` implied by `-D warnings`
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:11:1
+ --> $DIR/doc_errors.rs:12:1
|
LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:16:1
+ --> $DIR/doc_errors.rs:17:1
|
LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:21:1
+ --> $DIR/doc_errors.rs:22:1
|
LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:51:5
+ --> $DIR/doc_errors.rs:52:5
|
LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_____^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:56:5
+ --> $DIR/doc_errors.rs:57:5
|
LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_____^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:85:5
+ --> $DIR/doc_errors.rs:86:5
|
LL | fn trait_method_missing_errors_header() -> Result<(), ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![warn(clippy::drop_ref)]
#![allow(clippy::toplevel_ref_arg)]
#![allow(clippy::map_err_ignore)]
+#![allow(clippy::unnecessary_wraps)]
use std::mem::drop;
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:10:5
+ --> $DIR/drop_ref.rs:11:5
|
LL | drop(&SomeStruct);
| ^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::drop-ref` implied by `-D warnings`
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:10:10
+ --> $DIR/drop_ref.rs:11:10
|
LL | drop(&SomeStruct);
| ^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:13:5
+ --> $DIR/drop_ref.rs:14:5
|
LL | drop(&owned1);
| ^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:13:10
+ --> $DIR/drop_ref.rs:14:10
|
LL | drop(&owned1);
| ^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:14:5
+ --> $DIR/drop_ref.rs:15:5
|
LL | drop(&&owned1);
| ^^^^^^^^^^^^^^
|
note: argument has type `&&SomeStruct`
- --> $DIR/drop_ref.rs:14:10
+ --> $DIR/drop_ref.rs:15:10
|
LL | drop(&&owned1);
| ^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:15:5
+ --> $DIR/drop_ref.rs:16:5
|
LL | drop(&mut owned1);
| ^^^^^^^^^^^^^^^^^
|
note: argument has type `&mut SomeStruct`
- --> $DIR/drop_ref.rs:15:10
+ --> $DIR/drop_ref.rs:16:10
|
LL | drop(&mut owned1);
| ^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:19:5
+ --> $DIR/drop_ref.rs:20:5
|
LL | drop(reference1);
| ^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:19:10
+ --> $DIR/drop_ref.rs:20:10
|
LL | drop(reference1);
| ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:22:5
+ --> $DIR/drop_ref.rs:23:5
|
LL | drop(reference2);
| ^^^^^^^^^^^^^^^^
|
note: argument has type `&mut SomeStruct`
- --> $DIR/drop_ref.rs:22:10
+ --> $DIR/drop_ref.rs:23:10
|
LL | drop(reference2);
| ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:25:5
+ --> $DIR/drop_ref.rs:26:5
|
LL | drop(reference3);
| ^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:25:10
+ --> $DIR/drop_ref.rs:26:10
|
LL | drop(reference3);
| ^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:30:5
+ --> $DIR/drop_ref.rs:31:5
|
LL | drop(&val);
| ^^^^^^^^^^
|
note: argument has type `&T`
- --> $DIR/drop_ref.rs:30:10
+ --> $DIR/drop_ref.rs:31:10
|
LL | drop(&val);
| ^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
- --> $DIR/drop_ref.rs:38:5
+ --> $DIR/drop_ref.rs:39:5
|
LL | std::mem::drop(&SomeStruct);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/drop_ref.rs:38:20
+ --> $DIR/drop_ref.rs:39:20
|
LL | std::mem::drop(&SomeStruct);
| ^^^^^^^^^^^
| ^^^^^^^
|
= note: `-D clippy::empty-loop` implied by `-D warnings`
- = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+ = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
error: empty `loop {}` wastes CPU cycles
--> $DIR/empty_loop.rs:11:9
LL | loop {}
| ^^^^^^^
|
- = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+ = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
error: empty `loop {}` wastes CPU cycles
--> $DIR/empty_loop.rs:15:9
LL | 'inner: loop {}
| ^^^^^^^^^^^^^^^
|
- = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+ = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
error: aborting due to 3 previous errors
#[start]
fn main(argc: isize, argv: *const *const u8) -> isize {
+ // This should trigger the lint
loop {}
}
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
+ // This should NOT trigger the lint
loop {}
}
#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
+extern "C" fn eh_personality() {
+ // This should also trigger the lint
+ loop {}
+}
--- /dev/null
+error: empty `loop {}` wastes CPU cycles
+ --> $DIR/empty_loop_no_std.rs:14:5
+ |
+LL | loop {}
+ | ^^^^^^^
+ |
+ = note: `-D clippy::empty-loop` implied by `-D warnings`
+ = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
+
+error: empty `loop {}` wastes CPU cycles
+ --> $DIR/empty_loop_no_std.rs:26:5
+ |
+LL | loop {}
+ | ^^^^^^^
+ |
+ = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
+
+error: aborting due to 2 previous errors
+
#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::clippy::let_underscore_drop)]
#![allow(clippy::missing_docs_in_private_items)]
fn main() {
error: called `filter(..).map(..)` on an `Iterator`
- --> $DIR/filter_methods.rs:5:21
+ --> $DIR/filter_methods.rs:6:21
|
LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: this is more succinctly expressed by calling `.filter_map(..)` instead
error: called `filter(..).flat_map(..)` on an `Iterator`
- --> $DIR/filter_methods.rs:7:21
+ --> $DIR/filter_methods.rs:8:21
|
LL | let _: Vec<_> = vec![5_i8; 6]
| _____________________^
= help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
error: called `filter_map(..).flat_map(..)` on an `Iterator`
- --> $DIR/filter_methods.rs:13:21
+ --> $DIR/filter_methods.rs:14:21
|
LL | let _: Vec<_> = vec![5_i8; 6]
| _____________________^
= help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
error: called `filter_map(..).map(..)` on an `Iterator`
- --> $DIR/filter_methods.rs:19:21
+ --> $DIR/filter_methods.rs:20:21
|
LL | let _: Vec<_> = vec![5_i8; 6]
| _____________________^
#![warn(clippy::forget_ref)]
#![allow(clippy::toplevel_ref_arg)]
+#![allow(clippy::unnecessary_wraps)]
use std::mem::forget;
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:9:5
+ --> $DIR/forget_ref.rs:10:5
|
LL | forget(&SomeStruct);
| ^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::forget-ref` implied by `-D warnings`
note: argument has type `&SomeStruct`
- --> $DIR/forget_ref.rs:9:12
+ --> $DIR/forget_ref.rs:10:12
|
LL | forget(&SomeStruct);
| ^^^^^^^^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:12:5
+ --> $DIR/forget_ref.rs:13:5
|
LL | forget(&owned);
| ^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/forget_ref.rs:12:12
+ --> $DIR/forget_ref.rs:13:12
|
LL | forget(&owned);
| ^^^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:13:5
+ --> $DIR/forget_ref.rs:14:5
|
LL | forget(&&owned);
| ^^^^^^^^^^^^^^^
|
note: argument has type `&&SomeStruct`
- --> $DIR/forget_ref.rs:13:12
+ --> $DIR/forget_ref.rs:14:12
|
LL | forget(&&owned);
| ^^^^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:14:5
+ --> $DIR/forget_ref.rs:15:5
|
LL | forget(&mut owned);
| ^^^^^^^^^^^^^^^^^^
|
note: argument has type `&mut SomeStruct`
- --> $DIR/forget_ref.rs:14:12
+ --> $DIR/forget_ref.rs:15:12
|
LL | forget(&mut owned);
| ^^^^^^^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:18:5
+ --> $DIR/forget_ref.rs:19:5
|
LL | forget(&*reference1);
| ^^^^^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/forget_ref.rs:18:12
+ --> $DIR/forget_ref.rs:19:12
|
LL | forget(&*reference1);
| ^^^^^^^^^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:21:5
+ --> $DIR/forget_ref.rs:22:5
|
LL | forget(reference2);
| ^^^^^^^^^^^^^^^^^^
|
note: argument has type `&mut SomeStruct`
- --> $DIR/forget_ref.rs:21:12
+ --> $DIR/forget_ref.rs:22:12
|
LL | forget(reference2);
| ^^^^^^^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:24:5
+ --> $DIR/forget_ref.rs:25:5
|
LL | forget(reference3);
| ^^^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/forget_ref.rs:24:12
+ --> $DIR/forget_ref.rs:25:12
|
LL | forget(reference3);
| ^^^^^^^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:29:5
+ --> $DIR/forget_ref.rs:30:5
|
LL | forget(&val);
| ^^^^^^^^^^^^
|
note: argument has type `&T`
- --> $DIR/forget_ref.rs:29:12
+ --> $DIR/forget_ref.rs:30:12
|
LL | forget(&val);
| ^^^^
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
- --> $DIR/forget_ref.rs:37:5
+ --> $DIR/forget_ref.rs:38:5
|
LL | std::mem::forget(&SomeStruct);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: argument has type `&SomeStruct`
- --> $DIR/forget_ref.rs:37:22
+ --> $DIR/forget_ref.rs:38:22
|
LL | std::mem::forget(&SomeStruct);
| ^^^^^^^^^^^
--- /dev/null
+#![warn(clippy::let_underscore_drop)]
+
+struct Droppable;
+
+impl Drop for Droppable {
+ fn drop(&mut self) {}
+}
+
+fn main() {
+ let unit = ();
+ let boxed = Box::new(());
+ let droppable = Droppable;
+ let optional = Some(Droppable);
+
+ let _ = ();
+ let _ = Box::new(());
+ let _ = Droppable;
+ let _ = Some(Droppable);
+}
--- /dev/null
+error: non-binding `let` on a type that implements `Drop`
+ --> $DIR/let_underscore_drop.rs:16:5
+ |
+LL | let _ = Box::new(());
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::let-underscore-drop` implied by `-D warnings`
+ = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding `let` on a type that implements `Drop`
+ --> $DIR/let_underscore_drop.rs:17:5
+ |
+LL | let _ = Droppable;
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding `let` on a type that implements `Drop`
+ --> $DIR/let_underscore_drop.rs:18:5
+ |
+LL | let _ = Some(Droppable);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: aborting due to 3 previous errors
+
#![warn(clippy::let_underscore_must_use)]
+#![allow(clippy::unnecessary_wraps)]
// Debug implementations can fire this lint,
// so we shouldn't lint external macros
error: non-binding let on a result of a `#[must_use]` function
- --> $DIR/let_underscore_must_use.rs:66:5
+ --> $DIR/let_underscore_must_use.rs:67:5
|
LL | let _ = f();
| ^^^^^^^^^^^^
= help: consider explicitly using function result
error: non-binding let on an expression with `#[must_use]` type
- --> $DIR/let_underscore_must_use.rs:67:5
+ --> $DIR/let_underscore_must_use.rs:68:5
|
LL | let _ = g();
| ^^^^^^^^^^^^
= help: consider explicitly using expression value
error: non-binding let on a result of a `#[must_use]` function
- --> $DIR/let_underscore_must_use.rs:69:5
+ --> $DIR/let_underscore_must_use.rs:70:5
|
LL | let _ = l(0_u32);
| ^^^^^^^^^^^^^^^^^
= help: consider explicitly using function result
error: non-binding let on a result of a `#[must_use]` function
- --> $DIR/let_underscore_must_use.rs:73:5
+ --> $DIR/let_underscore_must_use.rs:74:5
|
LL | let _ = s.f();
| ^^^^^^^^^^^^^^
= help: consider explicitly using function result
error: non-binding let on an expression with `#[must_use]` type
- --> $DIR/let_underscore_must_use.rs:74:5
+ --> $DIR/let_underscore_must_use.rs:75:5
|
LL | let _ = s.g();
| ^^^^^^^^^^^^^^
= help: consider explicitly using expression value
error: non-binding let on a result of a `#[must_use]` function
- --> $DIR/let_underscore_must_use.rs:77:5
+ --> $DIR/let_underscore_must_use.rs:78:5
|
LL | let _ = S::h();
| ^^^^^^^^^^^^^^^
= help: consider explicitly using function result
error: non-binding let on an expression with `#[must_use]` type
- --> $DIR/let_underscore_must_use.rs:78:5
+ --> $DIR/let_underscore_must_use.rs:79:5
|
LL | let _ = S::p();
| ^^^^^^^^^^^^^^^
= help: consider explicitly using expression value
error: non-binding let on a result of a `#[must_use]` function
- --> $DIR/let_underscore_must_use.rs:80:5
+ --> $DIR/let_underscore_must_use.rs:81:5
|
LL | let _ = S::a();
| ^^^^^^^^^^^^^^^
= help: consider explicitly using function result
error: non-binding let on an expression with `#[must_use]` type
- --> $DIR/let_underscore_must_use.rs:82:5
+ --> $DIR/let_underscore_must_use.rs:83:5
|
LL | let _ = if true { Ok(()) } else { Err(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider explicitly using expression value
error: non-binding let on a result of a `#[must_use]` function
- --> $DIR/let_underscore_must_use.rs:86:5
+ --> $DIR/let_underscore_must_use.rs:87:5
|
LL | let _ = a.is_ok();
| ^^^^^^^^^^^^^^^^^^
= help: consider explicitly using function result
error: non-binding let on an expression with `#[must_use]` type
- --> $DIR/let_underscore_must_use.rs:88:5
+ --> $DIR/let_underscore_must_use.rs:89:5
|
LL | let _ = a.map(|_| ());
| ^^^^^^^^^^^^^^^^^^^^^^
= help: consider explicitly using expression value
error: non-binding let on an expression with `#[must_use]` type
- --> $DIR/let_underscore_must_use.rs:90:5
+ --> $DIR/let_underscore_must_use.rs:91:5
|
LL | let _ = a;
| ^^^^^^^^^^
-#![allow(unused, clippy::many_single_char_names)]
+#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)]
#![warn(clippy::logic_bug)]
fn main() {
async fn fut() -> i32 { 42 }
-async fn empty_fut() {}
+#[rustfmt::skip]
+async fn fut2() -> i32 { 42 }
+
+#[rustfmt::skip]
+async fn fut3() -> i32 { 42 }
+
+async fn empty_fut() {}
+
+#[rustfmt::skip]
+async fn empty_fut2() {}
+
+#[rustfmt::skip]
+async fn empty_fut3() {}
async fn core_fut() -> i32 { 42 }
async { 42 }
}
+#[rustfmt::skip]
+fn fut2() ->impl Future<Output = i32> {
+ async { 42 }
+}
+
+#[rustfmt::skip]
+fn fut3()-> impl Future<Output = i32> {
+ async { 42 }
+}
+
fn empty_fut() -> impl Future<Output = ()> {
async {}
}
+#[rustfmt::skip]
+fn empty_fut2() ->impl Future<Output = ()> {
+ async {}
+}
+
+#[rustfmt::skip]
+fn empty_fut3()-> impl Future<Output = ()> {
+ async {}
+}
+
fn core_fut() -> impl core::future::Future<Output = i32> {
async move { 42 }
}
| ^^^^^^
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:12:1
+ --> $DIR/manual_async_fn.rs:13:1
+ |
+LL | fn fut2() ->impl Future<Output = i32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: make the function `async` and return the output of the future directly
+ |
+LL | async fn fut2() -> i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+ |
+LL | fn fut2() ->impl Future<Output = i32> { 42 }
+ | ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+ --> $DIR/manual_async_fn.rs:18:1
+ |
+LL | fn fut3()-> impl Future<Output = i32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: make the function `async` and return the output of the future directly
+ |
+LL | async fn fut3() -> i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+ |
+LL | fn fut3()-> impl Future<Output = i32> { 42 }
+ | ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+ --> $DIR/manual_async_fn.rs:22:1
|
LL | fn empty_fut() -> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `async` and remove the return type
|
-LL | async fn empty_fut() {
+LL | async fn empty_fut() {
| ^^^^^^^^^^^^^^^^^^^^
help: move the body of the async block to the enclosing function
|
| ^^
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:16:1
+ --> $DIR/manual_async_fn.rs:27:1
+ |
+LL | fn empty_fut2() ->impl Future<Output = ()> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: make the function `async` and remove the return type
+ |
+LL | async fn empty_fut2() {
+ | ^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+ |
+LL | fn empty_fut2() ->impl Future<Output = ()> {}
+ | ^^
+
+error: this function can be simplified using the `async fn` syntax
+ --> $DIR/manual_async_fn.rs:32:1
+ |
+LL | fn empty_fut3()-> impl Future<Output = ()> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: make the function `async` and remove the return type
+ |
+LL | async fn empty_fut3() {
+ | ^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+ |
+LL | fn empty_fut3()-> impl Future<Output = ()> {}
+ | ^^
+
+error: this function can be simplified using the `async fn` syntax
+ --> $DIR/manual_async_fn.rs:36:1
|
LL | fn core_fut() -> impl core::future::Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:38:5
+ --> $DIR/manual_async_fn.rs:58:5
|
LL | fn inh_fut() -> impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:73:1
+ --> $DIR/manual_async_fn.rs:93:1
|
LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:82:1
+ --> $DIR/manual_async_fn.rs:102:1
|
LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { 42 }
| ^^^^^^
-error: aborting due to 6 previous errors
+error: aborting due to 10 previous errors
// not applicable, or side isn't `Result::Err`
foo.map_or(Ok::<i32, &str>(1), |v| Ok(v));
- // not applicatble, expr is not a `Result` value
+ // not applicable, expr is not a `Result` value
foo.map_or(42, |v| v);
// TODO patterns not covered yet
// not applicable, or side isn't `Result::Err`
foo.map_or(Ok::<i32, &str>(1), |v| Ok(v));
- // not applicatble, expr is not a `Result` value
+ // not applicable, expr is not a `Result` value
foo.map_or(42, |v| v);
// TODO patterns not covered yet
// run-rustfix
#![allow(dead_code)]
-#![allow(unused_variables)]
+#![allow(unused_variables, clippy::unnecessary_wraps)]
fn option_unwrap_or() {
// int case
// run-rustfix
#![allow(dead_code)]
-#![allow(unused_variables)]
+#![allow(unused_variables, clippy::unnecessary_wraps)]
fn option_unwrap_or() {
// int case
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::iter_cloned_collect)]
#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
+#![allow(clippy::let_underscore_drop)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::redundant_closure_for_method_calls)]
#![allow(clippy::many_single_char_names)]
let v = vec![&mut d];
let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
}
+
+ // Issue #6299
+ {
+ let mut aa = 5;
+ let mut bb = 3;
+ let items = vec![&mut aa, &mut bb];
+ let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect();
+ }
+
+ // Issue #6239 deref coercion and clone deref
+ {
+ use std::cell::RefCell;
+
+ let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
+ }
}
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::iter_cloned_collect)]
#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
+#![allow(clippy::let_underscore_drop)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::redundant_closure_for_method_calls)]
#![allow(clippy::many_single_char_names)]
let v = vec![&mut d];
let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
}
+
+ // Issue #6299
+ {
+ let mut aa = 5;
+ let mut bb = 3;
+ let items = vec![&mut aa, &mut bb];
+ let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect();
+ }
+
+ // Issue #6239 deref coercion and clone deref
+ {
+ use std::cell::RefCell;
+
+ let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
+ }
}
error: you are using an explicit closure for copying elements
- --> $DIR/map_clone.rs:10:22
+ --> $DIR/map_clone.rs:11:22
|
LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
= note: `-D clippy::map-clone` implied by `-D warnings`
error: you are using an explicit closure for cloning elements
- --> $DIR/map_clone.rs:11:26
+ --> $DIR/map_clone.rs:12:26
|
LL | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
error: you are using an explicit closure for copying elements
- --> $DIR/map_clone.rs:12:23
+ --> $DIR/map_clone.rs:13:23
|
LL | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
error: you are using an explicit closure for copying elements
- --> $DIR/map_clone.rs:14:26
+ --> $DIR/map_clone.rs:15:26
|
LL | let _: Option<u64> = Some(&16).map(|b| *b);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
error: you are using an explicit closure for copying elements
- --> $DIR/map_clone.rs:15:25
+ --> $DIR/map_clone.rs:16:25
|
LL | let _: Option<u8> = Some(&1).map(|x| x.clone());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
error: you are needlessly cloning iterator elements
- --> $DIR/map_clone.rs:26:29
+ --> $DIR/map_clone.rs:27:29
|
LL | let _ = std::env::args().map(|v| v.clone());
| ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call
#![warn(clippy::map_err_ignore)]
+#![allow(clippy::unnecessary_wraps)]
use std::convert::TryFrom;
use std::error::Error;
use std::fmt;
error: `map_err(|_|...` ignores the original error
- --> $DIR/map_err.rs:22:32
+ --> $DIR/map_err.rs:23:32
|
LL | println!("{:?}", x.map_err(|_| Errors::Ignored));
| ^^^
// run-rustfix
#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::let_underscore_drop)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::map_identity)]
+#![allow(clippy::unnecessary_wraps)]
fn main() {
// mapping to Option on Iterator
// run-rustfix
#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::let_underscore_drop)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::map_identity)]
+#![allow(clippy::unnecessary_wraps)]
fn main() {
// mapping to Option on Iterator
error: called `map(..).flatten()` on an `Iterator`
- --> $DIR/map_flatten.rs:14:46
+ --> $DIR/map_flatten.rs:16:46
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)`
= note: `-D clippy::map-flatten` implied by `-D warnings`
error: called `map(..).flatten()` on an `Iterator`
- --> $DIR/map_flatten.rs:15:46
+ --> $DIR/map_flatten.rs:17:46
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)`
error: called `map(..).flatten()` on an `Iterator`
- --> $DIR/map_flatten.rs:16:46
+ --> $DIR/map_flatten.rs:18:46
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)`
error: called `map(..).flatten()` on an `Iterator`
- --> $DIR/map_flatten.rs:17:46
+ --> $DIR/map_flatten.rs:19:46
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))`
error: called `map(..).flatten()` on an `Iterator`
- --> $DIR/map_flatten.rs:20:46
+ --> $DIR/map_flatten.rs:22:46
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)`
error: called `map(..).flatten()` on an `Option`
- --> $DIR/map_flatten.rs:23:39
+ --> $DIR/map_flatten.rs:25:39
|
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
let _ = foo.filter().next();
}
-/// Checks implementation of `SEARCH_IS_SOME` lint.
-#[rustfmt::skip]
-fn search_is_some() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_some()`, single-line case.
- let _ = v.iter().find(|&x| *x < 0).is_some();
- let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
- let _ = (0..1).find(|x| *x == 0).is_some();
- let _ = v.iter().find(|x| **x == 0).is_some();
-
- // Check `find().is_some()`, multi-line case.
- let _ = v.iter().find(|&x| {
- *x < 0
- }
- ).is_some();
-
- // Check `position().is_some()`, single-line case.
- let _ = v.iter().position(|&x| x < 0).is_some();
-
- // Check `position().is_some()`, multi-line case.
- let _ = v.iter().position(|&x| {
- x < 0
- }
- ).is_some();
-
- // Check `rposition().is_some()`, single-line case.
- let _ = v.iter().rposition(|&x| x < 0).is_some();
-
- // Check `rposition().is_some()`, multi-line case.
- let _ = v.iter().rposition(|&x| {
- x < 0
- }
- ).is_some();
-
- // Check that we don't lint if the caller is not an `Iterator`.
- let foo = IteratorFalsePositives { foo: 0 };
- let _ = foo.find().is_some();
- let _ = foo.position().is_some();
- let _ = foo.rposition().is_some();
-}
-
fn main() {
filter_next();
- search_is_some();
}
|
= note: `-D clippy::filter-next` implied by `-D warnings`
-error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:143:22
- |
-LL | let _ = v.iter().find(|&x| *x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
- |
- = note: `-D clippy::search-is-some` implied by `-D warnings`
-
-error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:144:20
- |
-LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
-
-error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:145:20
- |
-LL | let _ = (0..1).find(|x| *x == 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
-
-error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:146:22
- |
-LL | let _ = v.iter().find(|x| **x == 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
-
-error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:149:13
- |
-LL | let _ = v.iter().find(|&x| {
- | _____________^
-LL | | *x < 0
-LL | | }
-LL | | ).is_some();
- | |______________________________^
-
-error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:155:22
- |
-LL | let _ = v.iter().position(|&x| x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
-
-error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:158:13
- |
-LL | let _ = v.iter().position(|&x| {
- | _____________^
-LL | | x < 0
-LL | | }
-LL | | ).is_some();
- | |______________________________^
-
-error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:164:22
- |
-LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
-
-error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
- --> $DIR/methods.rs:167:13
- |
-LL | let _ = v.iter().rposition(|&x| {
- | _____________^
-LL | | x < 0
-LL | | }
-LL | | ).is_some();
- | |______________________________^
-
-error: aborting due to 11 previous errors
+error: aborting due to 2 previous errors
#![warn(clippy::mismatched_target_os)]
#![allow(unused)]
-#[cfg(target_os = "cloudabi")]
-fn cloudabi() {}
-
#[cfg(target_os = "hermit")]
fn hermit() {}
fn none() {}
// list with conditions
-#[cfg(all(not(any(windows, target_os = "cloudabi")), target_os = "wasi"))]
+#[cfg(all(not(windows), target_os = "wasi"))]
fn list() {}
// windows is a valid target family, should be ignored
#![warn(clippy::mismatched_target_os)]
#![allow(unused)]
-#[cfg(cloudabi)]
-fn cloudabi() {}
-
#[cfg(hermit)]
fn hermit() {}
fn none() {}
// list with conditions
-#[cfg(all(not(any(windows, cloudabi)), wasi))]
+#[cfg(all(not(windows), wasi))]
fn list() {}
// windows is a valid target family, should be ignored
error: operating system used in target family position
--> $DIR/mismatched_target_os_non_unix.rs:6:1
|
-LL | #[cfg(cloudabi)]
- | ^^^^^^--------^^
- | |
- | help: try: `target_os = "cloudabi"`
- |
- = note: `-D clippy::mismatched-target-os` implied by `-D warnings`
-
-error: operating system used in target family position
- --> $DIR/mismatched_target_os_non_unix.rs:9:1
- |
LL | #[cfg(hermit)]
| ^^^^^^------^^
| |
| help: try: `target_os = "hermit"`
+ |
+ = note: `-D clippy::mismatched-target-os` implied by `-D warnings`
error: operating system used in target family position
- --> $DIR/mismatched_target_os_non_unix.rs:12:1
+ --> $DIR/mismatched_target_os_non_unix.rs:9:1
|
LL | #[cfg(wasi)]
| ^^^^^^----^^
| help: try: `target_os = "wasi"`
error: operating system used in target family position
- --> $DIR/mismatched_target_os_non_unix.rs:15:1
+ --> $DIR/mismatched_target_os_non_unix.rs:12:1
|
LL | #[cfg(none)]
| ^^^^^^----^^
| help: try: `target_os = "none"`
error: operating system used in target family position
- --> $DIR/mismatched_target_os_non_unix.rs:19:1
- |
-LL | #[cfg(all(not(any(windows, cloudabi)), wasi))]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: try
- |
-LL | #[cfg(all(not(any(windows, target_os = "cloudabi")), wasi))]
- | ^^^^^^^^^^^^^^^^^^^^^^
-help: try
+ --> $DIR/mismatched_target_os_non_unix.rs:16:1
|
-LL | #[cfg(all(not(any(windows, cloudabi)), target_os = "wasi"))]
- | ^^^^^^^^^^^^^^^^^^
+LL | #[cfg(all(not(windows), wasi))]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^----^^^
+ | |
+ | help: try: `target_os = "wasi"`
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
#![warn(clippy::needless_lifetimes)]
-#![allow(dead_code, clippy::needless_pass_by_value)]
+#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)]
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
-#![allow(unused, clippy::many_single_char_names)]
+#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)]
#![warn(clippy::nonminimal_bool)]
fn main() {
-#![allow(unused, clippy::many_single_char_names)]
+#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)]
#![warn(clippy::nonminimal_bool)]
fn methods_with_negation() {
#![warn(clippy::option_map_unit_fn)]
#![allow(unused)]
+#![allow(clippy::unnecessary_wraps)]
fn do_nothing<T>(_: T) {}
#![warn(clippy::option_map_unit_fn)]
#![allow(unused)]
+#![allow(clippy::unnecessary_wraps)]
fn do_nothing<T>(_: T) {}
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:38:5
+ --> $DIR/option_map_unit_fn_fixable.rs:39:5
|
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
= note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:40:5
+ --> $DIR/option_map_unit_fn_fixable.rs:41:5
|
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:42:5
+ --> $DIR/option_map_unit_fn_fixable.rs:43:5
|
LL | x.field.map(diverge);
| ^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:48:5
+ --> $DIR/option_map_unit_fn_fixable.rs:49:5
|
LL | x.field.map(|value| x.do_option_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:50:5
+ --> $DIR/option_map_unit_fn_fixable.rs:51:5
|
LL | x.field.map(|value| { x.do_option_plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:53:5
+ --> $DIR/option_map_unit_fn_fixable.rs:54:5
|
LL | x.field.map(|value| do_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:55:5
+ --> $DIR/option_map_unit_fn_fixable.rs:56:5
|
LL | x.field.map(|value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:57:5
+ --> $DIR/option_map_unit_fn_fixable.rs:58:5
|
LL | x.field.map(|value| { do_nothing(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:59:5
+ --> $DIR/option_map_unit_fn_fixable.rs:60:5
|
LL | x.field.map(|value| { { do_nothing(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:62:5
+ --> $DIR/option_map_unit_fn_fixable.rs:63:5
|
LL | x.field.map(|value| diverge(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:64:5
+ --> $DIR/option_map_unit_fn_fixable.rs:65:5
|
LL | x.field.map(|value| { diverge(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:66:5
+ --> $DIR/option_map_unit_fn_fixable.rs:67:5
|
LL | x.field.map(|value| { diverge(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:68:5
+ --> $DIR/option_map_unit_fn_fixable.rs:69:5
|
LL | x.field.map(|value| { { diverge(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:73:5
+ --> $DIR/option_map_unit_fn_fixable.rs:74:5
|
LL | x.field.map(|value| { let y = plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:75:5
+ --> $DIR/option_map_unit_fn_fixable.rs:76:5
|
LL | x.field.map(|value| { plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:77:5
+ --> $DIR/option_map_unit_fn_fixable.rs:78:5
|
LL | x.field.map(|value| { { plus_one(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:80:5
+ --> $DIR/option_map_unit_fn_fixable.rs:81:5
|
LL | x.field.map(|ref value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:82:5
+ --> $DIR/option_map_unit_fn_fixable.rs:83:5
|
LL | option().map(do_nothing);}
| ^^^^^^^^^^^^^^^^^^^^^^^^-
#![deny(clippy::option_option)]
+#![allow(clippy::unnecessary_wraps)]
fn input(_: Option<Option<u8>>) {}
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
#[serde(borrow)]
- // FIXME: should not lint here
- #[allow(clippy::option_option)]
foo: Option<Option<Cow<'a, str>>>,
}
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:3:13
+ --> $DIR/option_option.rs:4:13
|
LL | fn input(_: Option<Option<u8>>) {}
| ^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:5:16
+ --> $DIR/option_option.rs:6:16
|
LL | fn output() -> Option<Option<u8>> {
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:9:27
+ --> $DIR/option_option.rs:10:27
|
LL | fn output_nested() -> Vec<Option<Option<u8>>> {
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:14:30
+ --> $DIR/option_option.rs:15:30
|
LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:19:8
+ --> $DIR/option_option.rs:20:8
|
LL | x: Option<Option<u8>>,
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:23:23
+ --> $DIR/option_option.rs:24:23
|
LL | fn struct_fn() -> Option<Option<u8>> {
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:29:22
+ --> $DIR/option_option.rs:30:22
|
LL | fn trait_fn() -> Option<Option<u8>>;
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:33:11
+ --> $DIR/option_option.rs:34:11
|
LL | Tuple(Option<Option<u8>>),
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:34:17
+ --> $DIR/option_option.rs:35:17
|
LL | Struct { x: Option<Option<u8>> },
| ^^^^^^^^^^^^^^^^^^
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:77:14
+ --> $DIR/option_option.rs:76:14
|
LL | foo: Option<Option<Cow<'a, str>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![warn(clippy::or_fun_call)]
#![allow(dead_code)]
+#![allow(clippy::unnecessary_wraps)]
use std::collections::BTreeMap;
use std::collections::HashMap;
let opt = Some(1);
let hello = "Hello";
let _ = opt.ok_or(format!("{} world.", hello));
+
+ // index
+ let map = HashMap::<u64, u64>::new();
+ let _ = Some(1).unwrap_or_else(|| map[&1]);
+ let map = BTreeMap::<u64, u64>::new();
+ let _ = Some(1).unwrap_or_else(|| map[&1]);
+ // don't lint index vec
+ let vec = vec![1];
+ let _ = Some(1).unwrap_or(vec[1]);
}
struct Foo(u8);
#![warn(clippy::or_fun_call)]
#![allow(dead_code)]
+#![allow(clippy::unnecessary_wraps)]
use std::collections::BTreeMap;
use std::collections::HashMap;
let opt = Some(1);
let hello = "Hello";
let _ = opt.ok_or(format!("{} world.", hello));
+
+ // index
+ let map = HashMap::<u64, u64>::new();
+ let _ = Some(1).unwrap_or(map[&1]);
+ let map = BTreeMap::<u64, u64>::new();
+ let _ = Some(1).unwrap_or(map[&1]);
+ // don't lint index vec
+ let vec = vec![1];
+ let _ = Some(1).unwrap_or(vec[1]);
}
struct Foo(u8);
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:32:19
+ --> $DIR/or_fun_call.rs:33:19
|
LL | with_const_fn.unwrap_or(Duration::from_secs(5));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))`
= note: `-D clippy::or-fun-call` implied by `-D warnings`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:35:22
+ --> $DIR/or_fun_call.rs:36:22
|
LL | with_constructor.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:38:5
+ --> $DIR/or_fun_call.rs:39:5
|
LL | with_new.unwrap_or(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:41:21
+ --> $DIR/or_fun_call.rs:42:21
|
LL | with_const_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:44:14
+ --> $DIR/or_fun_call.rs:45:14
|
LL | with_err.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:47:19
+ --> $DIR/or_fun_call.rs:48:19
|
LL | with_err_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:50:5
+ --> $DIR/or_fun_call.rs:51:5
|
LL | with_default_trait.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:53:5
+ --> $DIR/or_fun_call.rs:54:5
|
LL | with_default_type.unwrap_or(u64::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:56:5
+ --> $DIR/or_fun_call.rs:57:5
|
LL | with_vec.unwrap_or(vec![]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:59:21
+ --> $DIR/or_fun_call.rs:60:21
|
LL | without_default.unwrap_or(Foo::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
error: use of `or_insert` followed by a function call
- --> $DIR/or_fun_call.rs:62:19
+ --> $DIR/or_fun_call.rs:63:19
|
LL | map.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
error: use of `or_insert` followed by a function call
- --> $DIR/or_fun_call.rs:65:21
+ --> $DIR/or_fun_call.rs:66:21
|
LL | btree.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:68:21
+ --> $DIR/or_fun_call.rs:69:21
|
LL | let _ = stringy.unwrap_or("".to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
+error: use of `unwrap_or` followed by a function call
+ --> $DIR/or_fun_call.rs:77:21
+ |
+LL | let _ = Some(1).unwrap_or(map[&1]);
+ | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
+
+error: use of `unwrap_or` followed by a function call
+ --> $DIR/or_fun_call.rs:79:21
+ |
+LL | let _ = Some(1).unwrap_or(map[&1]);
+ | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
+
error: use of `or` followed by a function call
- --> $DIR/or_fun_call.rs:93:35
+ --> $DIR/or_fun_call.rs:103:35
|
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
error: use of `or` followed by a function call
- --> $DIR/or_fun_call.rs:97:10
+ --> $DIR/or_fun_call.rs:107:10
|
LL | .or(Some(Bar(b, Duration::from_secs(2))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
-error: aborting due to 15 previous errors
+error: aborting due to 17 previous errors
+++ /dev/null
-#![warn(clippy::panic_params)]
-#![allow(clippy::assertions_on_constants)]
-fn missing() {
- if true {
- panic!("{}");
- } else if false {
- panic!("{:?}");
- } else {
- assert!(true, "here be missing values: {}");
- }
-
- panic!("{{{this}}}");
-}
-
-fn ok_single() {
- panic!("foo bar");
-}
-
-fn ok_inner() {
- // Test for #768
- assert!("foo bar".contains(&format!("foo {}", "bar")));
-}
-
-fn ok_multiple() {
- panic!("{}", "This is {ok}");
-}
-
-fn ok_bracket() {
- match 42 {
- 1337 => panic!("{so is this"),
- 666 => panic!("so is this}"),
- _ => panic!("}so is that{"),
- }
-}
-
-const ONE: u32 = 1;
-
-fn ok_nomsg() {
- assert!({ 1 == ONE });
- assert!(if 1 == ONE { ONE == 1 } else { false });
-}
-
-fn ok_escaped() {
- panic!("{{ why should this not be ok? }}");
- panic!(" or {{ that ?");
- panic!(" or }} this ?");
- panic!(" {or {{ that ?");
- panic!(" }or }} this ?");
- panic!("{{ test }");
- panic!("{case }}");
-}
-
-fn main() {
- missing();
- ok_single();
- ok_multiple();
- ok_bracket();
- ok_inner();
- ok_nomsg();
- ok_escaped();
-}
+++ /dev/null
-error: you probably are missing some parameter in your format string
- --> $DIR/panic.rs:5:16
- |
-LL | panic!("{}");
- | ^^^^
- |
- = note: `-D clippy::panic-params` implied by `-D warnings`
-
-error: you probably are missing some parameter in your format string
- --> $DIR/panic.rs:7:16
- |
-LL | panic!("{:?}");
- | ^^^^^^
-
-error: you probably are missing some parameter in your format string
- --> $DIR/panic.rs:9:23
- |
-LL | assert!(true, "here be missing values: {}");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you probably are missing some parameter in your format string
- --> $DIR/panic.rs:12:12
- |
-LL | panic!("{{{this}}}");
- | ^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
#![warn(clippy::panic_in_result_fn)]
+#![allow(clippy::unnecessary_wraps)]
struct A;
error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:6:5
+ --> $DIR/panic_in_result_fn.rs:7:5
|
LL | / fn result_with_panic() -> Result<bool, String> // should emit lint
LL | | {
= note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
= help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:8:9
+ --> $DIR/panic_in_result_fn.rs:9:9
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:11:5
+ --> $DIR/panic_in_result_fn.rs:12:5
|
LL | / fn result_with_unimplemented() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:13:9
+ --> $DIR/panic_in_result_fn.rs:14:9
|
LL | unimplemented!();
| ^^^^^^^^^^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:16:5
+ --> $DIR/panic_in_result_fn.rs:17:5
|
LL | / fn result_with_unreachable() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:18:9
+ --> $DIR/panic_in_result_fn.rs:19:9
|
LL | unreachable!();
| ^^^^^^^^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:21:5
+ --> $DIR/panic_in_result_fn.rs:22:5
|
LL | / fn result_with_todo() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:23:9
+ --> $DIR/panic_in_result_fn.rs:24:9
|
LL | todo!("Finish this");
| ^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:52:1
+ --> $DIR/panic_in_result_fn.rs:53:1
|
LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:54:5
+ --> $DIR/panic_in_result_fn.rs:55:5
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:67:1
+ --> $DIR/panic_in_result_fn.rs:68:1
|
LL | / fn main() -> Result<(), String> {
LL | | todo!("finish main method");
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:68:5
+ --> $DIR/panic_in_result_fn.rs:69:5
|
LL | todo!("finish main method");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// run-rustfix
#![allow(unreachable_code)]
+#![allow(clippy::unnecessary_wraps)]
fn some_func(a: Option<u32>) -> Option<u32> {
a?;
// run-rustfix
#![allow(unreachable_code)]
+#![allow(clippy::unnecessary_wraps)]
fn some_func(a: Option<u32>) -> Option<u32> {
if a.is_none() {
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:5:5
+ --> $DIR/question_mark.rs:6:5
|
LL | / if a.is_none() {
LL | | return None;
= note: `-D clippy::question-mark` implied by `-D warnings`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:50:9
+ --> $DIR/question_mark.rs:51:9
|
LL | / if (self.opt).is_none() {
LL | | return None;
| |_________^ help: replace it with: `(self.opt)?;`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:54:9
+ --> $DIR/question_mark.rs:55:9
|
LL | / if self.opt.is_none() {
LL | | return None
| |_________^ help: replace it with: `self.opt?;`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:58:17
+ --> $DIR/question_mark.rs:59:17
|
LL | let _ = if self.opt.is_none() {
| _________________^
| |_________^ help: replace it with: `Some(self.opt?)`
error: this if-let-else may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:64:17
+ --> $DIR/question_mark.rs:65:17
|
LL | let _ = if let Some(x) = self.opt {
| _________________^
| |_________^ help: replace it with: `self.opt?`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:81:9
+ --> $DIR/question_mark.rs:82:9
|
LL | / if self.opt.is_none() {
LL | | return None;
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:89:9
+ --> $DIR/question_mark.rs:90:9
|
LL | / if self.opt.is_none() {
LL | | return None;
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:97:9
+ --> $DIR/question_mark.rs:98:9
|
LL | / if self.opt.is_none() {
LL | | return None;
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this if-let-else may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:104:26
+ --> $DIR/question_mark.rs:105:26
|
LL | let v: &Vec<_> = if let Some(ref v) = self.opt {
| __________________________^
| |_________^ help: replace it with: `self.opt.as_ref()?`
error: this if-let-else may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:114:17
+ --> $DIR/question_mark.rs:115:17
|
LL | let v = if let Some(v) = self.opt {
| _________________^
| |_________^ help: replace it with: `self.opt?`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:129:5
+ --> $DIR/question_mark.rs:130:5
|
LL | / if f().is_none() {
LL | | return None;
x >= 8 || x >= 12;
x < 12 || 12 < x;
x >= 8 || x <= 12;
+
+ // Fix #6315
+ let y = 3.;
+ (0. ..1.).contains(&y);
+ !(0. ..=1.).contains(&y);
}
x >= 8 || x >= 12;
x < 12 || 12 < x;
x >= 8 || x <= 12;
+
+ // Fix #6315
+ let y = 3.;
+ y >= 0. && y < 1.;
+ y < 0. || y > 1.;
}
LL | 999 < x || 1 > x;
| ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
-error: aborting due to 12 previous errors
+error: manual `Range::contains` implementation
+ --> $DIR/range_contains.rs:44:5
+ |
+LL | y >= 0. && y < 1.;
+ | ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
+
+error: manual `!RangeInclusive::contains` implementation
+ --> $DIR/range_contains.rs:45:5
+ |
+LL | y < 0. || y > 1.;
+ | ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
+
+error: aborting due to 14 previous errors
unused_must_use,
clippy::needless_bool,
clippy::match_like_matches_macro,
+ clippy::unnecessary_wraps,
deprecated
)]
unused_must_use,
clippy::needless_bool,
clippy::match_like_matches_macro,
+ clippy::unnecessary_wraps,
deprecated
)]
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:15:12
+ --> $DIR/redundant_pattern_matching.rs:16:12
|
LL | if let Ok(_) = &result {}
| -------^^^^^---------- help: try this: `if result.is_ok()`
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:17:12
+ --> $DIR/redundant_pattern_matching.rs:18:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:19:12
+ --> $DIR/redundant_pattern_matching.rs:20:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:21:15
+ --> $DIR/redundant_pattern_matching.rs:22:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:23:15
+ --> $DIR/redundant_pattern_matching.rs:24:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:33:5
+ --> $DIR/redundant_pattern_matching.rs:34:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:38:5
+ --> $DIR/redundant_pattern_matching.rs:39:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => false,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:43:5
+ --> $DIR/redundant_pattern_matching.rs:44:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:48:5
+ --> $DIR/redundant_pattern_matching.rs:49:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => true,
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:53:20
+ --> $DIR/redundant_pattern_matching.rs:54:20
|
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:59:20
+ --> $DIR/redundant_pattern_matching.rs:60:20
|
LL | let _ = if let Ok(_) = gen_res() {
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:61:19
+ --> $DIR/redundant_pattern_matching.rs:62:19
|
LL | } else if let Err(_) = gen_res() {
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:84:19
+ --> $DIR/redundant_pattern_matching.rs:85:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:85:16
+ --> $DIR/redundant_pattern_matching.rs:86:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:91:12
+ --> $DIR/redundant_pattern_matching.rs:92:12
|
LL | if let Some(_) = m!() {}
| -------^^^^^^^------- help: try this: `if m!().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:92:15
+ --> $DIR/redundant_pattern_matching.rs:93:15
|
LL | while let Some(_) = m!() {}
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:110:12
+ --> $DIR/redundant_pattern_matching.rs:111:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:112:12
+ --> $DIR/redundant_pattern_matching.rs:113:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:114:15
+ --> $DIR/redundant_pattern_matching.rs:115:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:116:15
+ --> $DIR/redundant_pattern_matching.rs:117:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:118:5
+ --> $DIR/redundant_pattern_matching.rs:119:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:123:5
+ --> $DIR/redundant_pattern_matching.rs:124:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
+#![allow(clippy::unnecessary_wraps)]
#[warn(clippy::result_unit_err)]
#[allow(unused)]
error: this returns a `Result<_, ()>
- --> $DIR/result_unit_error.rs:4:1
+ --> $DIR/result_unit_error.rs:5:1
|
LL | pub fn returns_unit_error() -> Result<u32, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom Error type instead
error: this returns a `Result<_, ()>
- --> $DIR/result_unit_error.rs:13:5
+ --> $DIR/result_unit_error.rs:14:5
|
LL | fn get_that_error(&self) -> Result<bool, ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom Error type instead
error: this returns a `Result<_, ()>
- --> $DIR/result_unit_error.rs:15:5
+ --> $DIR/result_unit_error.rs:16:5
|
LL | fn get_this_one_too(&self) -> Result<bool, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom Error type instead
error: this returns a `Result<_, ()>
- --> $DIR/result_unit_error.rs:33:5
+ --> $DIR/result_unit_error.rs:34:5
|
LL | pub fn unit_error(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// aux-build:option_helpers.rs
+extern crate option_helpers;
+use option_helpers::IteratorFalsePositives;
+
+#[warn(clippy::search_is_some)]
+#[rustfmt::skip]
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+
+ // Check `find().is_some()`, multi-line case.
+ let _ = v.iter().find(|&x| {
+ *x < 0
+ }
+ ).is_some();
+
+ // Check `position().is_some()`, multi-line case.
+ let _ = v.iter().position(|&x| {
+ x < 0
+ }
+ ).is_some();
+
+ // Check `rposition().is_some()`, multi-line case.
+ let _ = v.iter().rposition(|&x| {
+ x < 0
+ }
+ ).is_some();
+
+ // Check that we don't lint if the caller is not an `Iterator` or string
+ let falsepos = IteratorFalsePositives { foo: 0 };
+ let _ = falsepos.find().is_some();
+ let _ = falsepos.position().is_some();
+ let _ = falsepos.rposition().is_some();
+ // check that we don't lint if `find()` is called with
+ // `Pattern` that is not a string
+ let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some();
+}
--- /dev/null
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some.rs:13:13
+ |
+LL | let _ = v.iter().find(|&x| {
+ | _____________^
+LL | | *x < 0
+LL | | }
+LL | | ).is_some();
+ | |______________________________^
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+ = help: this is more succinctly expressed by calling `any()`
+
+error: called `is_some()` after searching an `Iterator` with `position`
+ --> $DIR/search_is_some.rs:19:13
+ |
+LL | let _ = v.iter().position(|&x| {
+ | _____________^
+LL | | x < 0
+LL | | }
+LL | | ).is_some();
+ | |______________________________^
+ |
+ = help: this is more succinctly expressed by calling `any()`
+
+error: called `is_some()` after searching an `Iterator` with `rposition`
+ --> $DIR/search_is_some.rs:25:13
+ |
+LL | let _ = v.iter().rposition(|&x| {
+ | _____________^
+LL | | x < 0
+LL | | }
+LL | | ).is_some();
+ | |______________________________^
+ |
+ = help: this is more succinctly expressed by calling `any()`
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// run-rustfix
+
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_some()`, single-line case.
+ let _ = v.iter().any(|x| *x < 0);
+ let _ = (0..1).any(|x| **y == x); // one dereference less
+ let _ = (0..1).any(|x| x == 0);
+ let _ = v.iter().any(|x| *x == 0);
+
+ // Check `position().is_some()`, single-line case.
+ let _ = v.iter().any(|&x| x < 0);
+
+ // Check `rposition().is_some()`, single-line case.
+ let _ = v.iter().any(|&x| x < 0);
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".contains("world");
+ let _ = "hello world".contains(&s2);
+ let _ = "hello world".contains(&s2[2..]);
+ // caller of `find()` is a `String`
+ let _ = s1.contains("world");
+ let _ = s1.contains(&s2);
+ let _ = s1.contains(&s2[2..]);
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].contains("world");
+ let _ = s1[2..].contains(&s2);
+ let _ = s1[2..].contains(&s2[2..]);
+}
--- /dev/null
+// run-rustfix
+
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_some()`, single-line case.
+ let _ = v.iter().find(|&x| *x < 0).is_some();
+ let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+ let _ = (0..1).find(|x| *x == 0).is_some();
+ let _ = v.iter().find(|x| **x == 0).is_some();
+
+ // Check `position().is_some()`, single-line case.
+ let _ = v.iter().position(|&x| x < 0).is_some();
+
+ // Check `rposition().is_some()`, single-line case.
+ let _ = v.iter().rposition(|&x| x < 0).is_some();
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".find("world").is_some();
+ let _ = "hello world".find(&s2).is_some();
+ let _ = "hello world".find(&s2[2..]).is_some();
+ // caller of `find()` is a `String`
+ let _ = s1.find("world").is_some();
+ let _ = s1.find(&s2).is_some();
+ let _ = s1.find(&s2[2..]).is_some();
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].find("world").is_some();
+ let _ = s1[2..].find(&s2).is_some();
+ let _ = s1[2..].find(&s2[2..]).is_some();
+}
--- /dev/null
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable.rs:10:22
+ |
+LL | let _ = v.iter().find(|&x| *x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)`
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable.rs:11:20
+ |
+LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable.rs:12:20
+ |
+LL | let _ = (0..1).find(|x| *x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable.rs:13:22
+ |
+LL | let _ = v.iter().find(|x| **x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `position`
+ --> $DIR/search_is_some_fixable.rs:16:22
+ |
+LL | let _ = v.iter().position(|&x| x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
+
+error: called `is_some()` after searching an `Iterator` with `rposition`
+ --> $DIR/search_is_some_fixable.rs:19:22
+ |
+LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:24:27
+ |
+LL | let _ = "hello world".find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:25:27
+ |
+LL | let _ = "hello world".find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:26:27
+ |
+LL | let _ = "hello world".find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:28:16
+ |
+LL | let _ = s1.find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:29:16
+ |
+LL | let _ = s1.find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:30:16
+ |
+LL | let _ = s1.find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:32:21
+ |
+LL | let _ = s1[2..].find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:33:21
+ |
+LL | let _ = s1[2..].find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable.rs:34:21
+ |
+LL | let _ = s1[2..].find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: aborting due to 15 previous errors
+
--- /dev/null
+// run-rustfix
+#![warn(clippy::string_from_utf8_as_bytes)]
+
+fn main() {
+ let _ = Some(&"Hello World!"[6..11]);
+}
--- /dev/null
+// run-rustfix
+#![warn(clippy::string_from_utf8_as_bytes)]
+
+fn main() {
+ let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]);
+}
--- /dev/null
+error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary
+ --> $DIR/string_from_utf8_as_bytes.rs:5:13
+ |
+LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])`
+ |
+ = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings`
+
+error: aborting due to previous error
+
// aux-build:macro_rules.rs
#![deny(clippy::try_err)]
+#![allow(clippy::unnecessary_wraps)]
#[macro_use]
extern crate macro_rules;
Ok(1)
}
+// Bad suggestion when in macro (see #6242)
+macro_rules! try_validation {
+ ($e: expr) => {{
+ match $e {
+ Ok(_) => 0,
+ Err(_) => return Err(1),
+ }
+ }};
+}
+
+macro_rules! ret_one {
+ () => {
+ 1
+ };
+}
+
+macro_rules! try_validation_in_macro {
+ ($e: expr) => {{
+ match $e {
+ Ok(_) => 0,
+ Err(_) => return Err(ret_one!()),
+ }
+ }};
+}
+
+fn calling_macro() -> Result<i32, i32> {
+ // macro
+ try_validation!(Ok::<_, i32>(5));
+ // `Err` arg is another macro
+ try_validation_in_macro!(Ok::<_, i32>(5));
+ Ok(5)
+}
+
fn main() {
basic_test().unwrap();
into_test().unwrap();
negative_test().unwrap();
closure_matches_test().unwrap();
closure_into_test().unwrap();
+ calling_macro().unwrap();
// We don't want to lint in external macros
try_err!();
// aux-build:macro_rules.rs
#![deny(clippy::try_err)]
+#![allow(clippy::unnecessary_wraps)]
#[macro_use]
extern crate macro_rules;
Ok(1)
}
+// Bad suggestion when in macro (see #6242)
+macro_rules! try_validation {
+ ($e: expr) => {{
+ match $e {
+ Ok(_) => 0,
+ Err(_) => Err(1)?,
+ }
+ }};
+}
+
+macro_rules! ret_one {
+ () => {
+ 1
+ };
+}
+
+macro_rules! try_validation_in_macro {
+ ($e: expr) => {{
+ match $e {
+ Ok(_) => 0,
+ Err(_) => Err(ret_one!())?,
+ }
+ }};
+}
+
+fn calling_macro() -> Result<i32, i32> {
+ // macro
+ try_validation!(Ok::<_, i32>(5));
+ // `Err` arg is another macro
+ try_validation_in_macro!(Ok::<_, i32>(5));
+ Ok(5)
+}
+
fn main() {
basic_test().unwrap();
into_test().unwrap();
negative_test().unwrap();
closure_matches_test().unwrap();
closure_into_test().unwrap();
+ calling_macro().unwrap();
// We don't want to lint in external macros
try_err!();
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:18:9
+ --> $DIR/try_err.rs:19:9
|
LL | Err(err)?;
| ^^^^^^^^^ help: try this: `return Err(err)`
| ^^^^^^^^^^^^^^^
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:28:9
+ --> $DIR/try_err.rs:29:9
|
LL | Err(err)?;
| ^^^^^^^^^ help: try this: `return Err(err.into())`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:48:17
+ --> $DIR/try_err.rs:49:17
|
LL | Err(err)?;
| ^^^^^^^^^ help: try this: `return Err(err)`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:67:17
+ --> $DIR/try_err.rs:68:17
|
LL | Err(err)?;
| ^^^^^^^^^ help: try this: `return Err(err.into())`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:106:9
+ --> $DIR/try_err.rs:87:23
+ |
+LL | Err(_) => Err(1)?,
+ | ^^^^^^^ help: try this: `return Err(1)`
+...
+LL | try_validation!(Ok::<_, i32>(5));
+ | --------------------------------- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: returning an `Err(_)` with the `?` operator
+ --> $DIR/try_err.rs:102:23
+ |
+LL | Err(_) => Err(ret_one!())?,
+ | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())`
+...
+LL | try_validation_in_macro!(Ok::<_, i32>(5));
+ | ------------------------------------------ in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: returning an `Err(_)` with the `?` operator
+ --> $DIR/try_err.rs:141:9
|
LL | Err(foo!())?;
| ^^^^^^^^^^^^ help: try this: `return Err(foo!())`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:113:9
+ --> $DIR/try_err.rs:148:9
|
LL | Err(io::ErrorKind::WriteZero)?
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:115:9
+ --> $DIR/try_err.rs:150:9
|
LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:123:9
+ --> $DIR/try_err.rs:158:9
|
LL | Err(io::ErrorKind::NotFound)?
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
unused_must_use,
unused_variables,
clippy::unused_unit,
+ clippy::unnecessary_wraps,
clippy::or_fun_call
)]
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:29:5
+ --> $DIR/unit_arg.rs:30:5
|
LL | / foo({
LL | | 1;
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:32:5
+ --> $DIR/unit_arg.rs:33:5
|
LL | foo(foo(1));
| ^^^^^^^^^^^
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:33:5
+ --> $DIR/unit_arg.rs:34:5
|
LL | / foo({
LL | | foo(1);
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:38:5
+ --> $DIR/unit_arg.rs:39:5
|
LL | / b.bar({
LL | | 1;
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:41:5
+ --> $DIR/unit_arg.rs:42:5
|
LL | taking_multiple_units(foo(0), foo(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:42:5
+ --> $DIR/unit_arg.rs:43:5
|
LL | / taking_multiple_units(foo(0), {
LL | | foo(1);
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:46:5
+ --> $DIR/unit_arg.rs:47:5
|
LL | / taking_multiple_units(
LL | | {
...
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:57:13
+ --> $DIR/unit_arg.rs:58:13
|
LL | None.or(Some(foo(2)));
| ^^^^^^^^^^^^
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:60:5
+ --> $DIR/unit_arg.rs:61:5
|
LL | foo(foo(()))
| ^^^^^^^^^^^^
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:93:5
+ --> $DIR/unit_arg.rs:94:5
|
LL | Some(foo(1))
| ^^^^^^^^^^^^
// does not test any rustfixable lints
#![warn(clippy::clone_on_ref_ptr)]
-#![allow(unused, clippy::redundant_clone)]
+#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)]
use std::cell::RefCell;
use std::rc::{self, Rc};
--- /dev/null
+#![warn(clippy::unnecessary_lazy_evaluations)]
+
+struct Deep(Option<usize>);
+
+#[derive(Copy, Clone)]
+struct SomeStruct {
+ some_field: usize,
+}
+
+fn main() {
+ // fix will break type inference
+ let _ = Ok(1).unwrap_or_else(|()| 2);
+ mod e {
+ pub struct E;
+ }
+ let _ = Ok(1).unwrap_or_else(|e::E| 2);
+ let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2);
+}
--- /dev/null
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13
+ |
+LL | let _ = Ok(1).unwrap_or_else(|()| 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)`
+ |
+ = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13
+ |
+LL | let _ = Ok(1).unwrap_or_else(|e::E| 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+ --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13
+ |
+LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)`
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+#![warn(clippy::unnecessary_wraps)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::needless_return)]
+#![allow(clippy::if_same_then_else)]
+#![allow(dead_code)]
+
+// should be linted
+fn func1(a: bool, b: bool) -> Option<i32> {
+ if a && b {
+ return Some(42);
+ }
+ if a {
+ Some(-1);
+ Some(2)
+ } else {
+ return Some(1337);
+ }
+}
+
+// should be linted
+fn func2(a: bool, b: bool) -> Option<i32> {
+ if a && b {
+ return Some(10);
+ }
+ if a {
+ Some(20)
+ } else {
+ Some(30)
+ }
+}
+
+// public fns should not be linted
+pub fn func3(a: bool) -> Option<i32> {
+ if a {
+ Some(1)
+ } else {
+ Some(1)
+ }
+}
+
+// should not be linted
+fn func4(a: bool) -> Option<i32> {
+ if a {
+ Some(1)
+ } else {
+ None
+ }
+}
+
+// should be linted
+fn func5() -> Option<i32> {
+ Some(1)
+}
+
+// should not be linted
+fn func6() -> Option<i32> {
+ None
+}
+
+// should be linted
+fn func7() -> Result<i32, ()> {
+ Ok(1)
+}
+
+// should not be linted
+fn func8(a: bool) -> Result<i32, ()> {
+ if a {
+ Ok(1)
+ } else {
+ Err(())
+ }
+}
+
+// should not be linted
+fn func9(a: bool) -> Result<i32, ()> {
+ Err(())
+}
+
+// should not be linted
+fn func10() -> Option<()> {
+ unimplemented!()
+}
+
+struct A;
+
+impl A {
+ // should not be linted
+ pub fn func11() -> Option<i32> {
+ Some(1)
+ }
+
+ // should be linted
+ fn func12() -> Option<i32> {
+ Some(1)
+ }
+}
+
+trait B {
+ // trait impls are not linted
+ fn func13() -> Option<i32> {
+ Some(1)
+ }
+}
+
+impl B for A {
+ // trait impls are not linted
+ fn func13() -> Option<i32> {
+ Some(0)
+ }
+}
+
+fn main() {
+ // method calls are not linted
+ func1(true, true);
+ func2(true, true);
+}
--- /dev/null
+error: this function's return value is unnecessarily wrapped by `Option`
+ --> $DIR/unnecessary_wraps.rs:8:1
+ |
+LL | / fn func1(a: bool, b: bool) -> Option<i32> {
+LL | | if a && b {
+LL | | return Some(42);
+LL | | }
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+ = note: `-D clippy::unnecessary-wraps` implied by `-D warnings`
+help: remove `Option` from the return type...
+ |
+LL | fn func1(a: bool, b: bool) -> i32 {
+ | ^^^
+help: ...and change the returning expressions
+ |
+LL | return 42;
+LL | }
+LL | if a {
+LL | Some(-1);
+LL | 2
+LL | } else {
+ ...
+
+error: this function's return value is unnecessarily wrapped by `Option`
+ --> $DIR/unnecessary_wraps.rs:21:1
+ |
+LL | / fn func2(a: bool, b: bool) -> Option<i32> {
+LL | | if a && b {
+LL | | return Some(10);
+LL | | }
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+help: remove `Option` from the return type...
+ |
+LL | fn func2(a: bool, b: bool) -> i32 {
+ | ^^^
+help: ...and change the returning expressions
+ |
+LL | return 10;
+LL | }
+LL | if a {
+LL | 20
+LL | } else {
+LL | 30
+ |
+
+error: this function's return value is unnecessarily wrapped by `Option`
+ --> $DIR/unnecessary_wraps.rs:51:1
+ |
+LL | / fn func5() -> Option<i32> {
+LL | | Some(1)
+LL | | }
+ | |_^
+ |
+help: remove `Option` from the return type...
+ |
+LL | fn func5() -> i32 {
+ | ^^^
+help: ...and change the returning expressions
+ |
+LL | 1
+ |
+
+error: this function's return value is unnecessarily wrapped by `Result`
+ --> $DIR/unnecessary_wraps.rs:61:1
+ |
+LL | / fn func7() -> Result<i32, ()> {
+LL | | Ok(1)
+LL | | }
+ | |_^
+ |
+help: remove `Result` from the return type...
+ |
+LL | fn func7() -> i32 {
+ | ^^^
+help: ...and change the returning expressions
+ |
+LL | 1
+ |
+
+error: this function's return value is unnecessarily wrapped by `Option`
+ --> $DIR/unnecessary_wraps.rs:93:5
+ |
+LL | / fn func12() -> Option<i32> {
+LL | | Some(1)
+LL | | }
+ | |_____^
+ |
+help: remove `Option` from the return type...
+ |
+LL | fn func12() -> i32 {
+ | ^^^
+help: ...and change the returning expressions
+ |
+LL | 1
+ |
+
+error: aborting due to 5 previous errors
+
// run-rustfix
#![deny(clippy::useless_conversion)]
+#![allow(clippy::unnecessary_wraps)]
fn test_generic<T: Copy>(val: T) -> T {
let _ = val;
// run-rustfix
#![deny(clippy::useless_conversion)]
+#![allow(clippy::unnecessary_wraps)]
fn test_generic<T: Copy>(val: T) -> T {
let _ = T::from(val);
error: useless conversion to the same type: `T`
- --> $DIR/useless_conversion.rs:6:13
+ --> $DIR/useless_conversion.rs:7:13
|
LL | let _ = T::from(val);
| ^^^^^^^^^^^^ help: consider removing `T::from()`: `val`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: useless conversion to the same type: `T`
- --> $DIR/useless_conversion.rs:7:5
+ --> $DIR/useless_conversion.rs:8:5
|
LL | val.into()
| ^^^^^^^^^^ help: consider removing `.into()`: `val`
error: useless conversion to the same type: `i32`
- --> $DIR/useless_conversion.rs:19:22
+ --> $DIR/useless_conversion.rs:20:22
|
LL | let _: i32 = 0i32.into();
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:60:21
+ --> $DIR/useless_conversion.rs:61:21
|
LL | let _: String = "foo".to_string().into();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:61:21
+ --> $DIR/useless_conversion.rs:62:21
|
LL | let _: String = From::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:62:13
+ --> $DIR/useless_conversion.rs:63:13
|
LL | let _ = String::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:63:13
+ --> $DIR/useless_conversion.rs:64:13
|
LL | let _ = String::from(format!("A: {:04}", 123));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
error: useless conversion to the same type: `std::str::Lines`
- --> $DIR/useless_conversion.rs:64:13
+ --> $DIR/useless_conversion.rs:65:13
|
LL | let _ = "".lines().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
error: useless conversion to the same type: `std::vec::IntoIter<i32>`
- --> $DIR/useless_conversion.rs:65:13
+ --> $DIR/useless_conversion.rs:66:13
|
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
error: useless conversion to the same type: `std::string::String`
- --> $DIR/useless_conversion.rs:66:21
+ --> $DIR/useless_conversion.rs:67:21
|
LL | let _: String = format!("Hello {}", "world").into();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
error: useless conversion to the same type: `i32`
- --> $DIR/useless_conversion.rs:71:13
+ --> $DIR/useless_conversion.rs:72:13
|
LL | let _ = i32::from(a + b) * 3;
| ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
}
}
+mod inner_mod {
+ mod inner {
+ pub struct S;
+ }
+
+ mod inner2 {
+ use super::inner::S;
+
+ pub fn f() -> Vec<S> {
+ vec![]
+ }
+ }
+}
+
fn main() {}
}
}
+mod inner_mod {
+ mod inner {
+ pub struct S;
+ }
+
+ mod inner2 {
+ use super::inner::S;
+
+ pub fn f() -> Vec<Box<S>> {
+ vec![]
+ }
+ }
+}
+
fn main() {}
LL | struct B(Vec<Vec<Box<(u32)>>>);
| ^^^^^^^^^^^^^^^ help: try: `Vec<u32>`
-error: aborting due to 3 previous errors
+error: `Vec<T>` is already on the heap, the boxing is unnecessary.
+ --> $DIR/vec_box_sized.rs:46:23
+ |
+LL | pub fn f() -> Vec<Box<S>> {
+ | ^^^^^^^^^^^ help: try: `Vec<S>`
+
+error: aborting due to 4 previous errors
dead_code,
clippy::single_match,
clippy::wildcard_in_or_patterns,
- clippy::unnested_or_patterns
+ clippy::unnested_or_patterns, clippy::diverging_sub_expression
)]
use std::io::ErrorKind;
dead_code,
clippy::single_match,
clippy::wildcard_in_or_patterns,
- clippy::unnested_or_patterns
+ clippy::unnested_or_patterns, clippy::diverging_sub_expression
)]
use std::io::ErrorKind;
#![warn(clippy::wildcard_imports)]
//#![allow(clippy::redundant_pub_crate)]
#![allow(unused)]
+#![allow(clippy::unnecessary_wraps)]
#![warn(unused_imports)]
extern crate wildcard_imports_helper;
#![warn(clippy::wildcard_imports)]
//#![allow(clippy::redundant_pub_crate)]
#![allow(unused)]
+#![allow(clippy::unnecessary_wraps)]
#![warn(unused_imports)]
extern crate wildcard_imports_helper;
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:11:5
+ --> $DIR/wildcard_imports.rs:12:5
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
= note: `-D clippy::wildcard-imports` implied by `-D warnings`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:12:5
+ --> $DIR/wildcard_imports.rs:13:5
|
LL | use crate::mod_mod::*;
| ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:13:5
+ --> $DIR/wildcard_imports.rs:14:5
|
LL | use crate::multi_fn_mod::*;
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:15:5
+ --> $DIR/wildcard_imports.rs:16:5
|
LL | use crate::struct_mod::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:19:5
+ --> $DIR/wildcard_imports.rs:20:5
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:20:5
+ --> $DIR/wildcard_imports.rs:21:5
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:91:13
+ --> $DIR/wildcard_imports.rs:92:13
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:97:75
+ --> $DIR/wildcard_imports.rs:98:75
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
| ^ help: try: `inner_extern_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:98:13
+ --> $DIR/wildcard_imports.rs:99:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:109:20
+ --> $DIR/wildcard_imports.rs:110:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:109:30
+ --> $DIR/wildcard_imports.rs:110:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:116:13
+ --> $DIR/wildcard_imports.rs:117:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:145:9
+ --> $DIR/wildcard_imports.rs:146:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:154:9
+ --> $DIR/wildcard_imports.rs:155:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:155:9
+ --> $DIR/wildcard_imports.rs:156:9
|
LL | use crate:: fn_mod::
| _________^
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:166:13
+ --> $DIR/wildcard_imports.rs:167:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:201:17
+ --> $DIR/wildcard_imports.rs:202:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:209:13
+ --> $DIR/wildcard_imports.rs:210:13
|
LL | use super_imports::*;
| ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:218:17
+ --> $DIR/wildcard_imports.rs:219:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:227:13
+ --> $DIR/wildcard_imports.rs:228:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
vec![]
} else {
- proc_res.fatal(Some(&format!(
- "failed to decode compiler output as json: \
+ proc_res.fatal(
+ Some(&format!(
+ "failed to decode compiler output as json: \
`{}`\nline: {}\noutput: {}",
- error, line, output
- )));
+ error, line, output
+ )),
+ || (),
+ );
}
}
}
}
Err(e) => {
// We don't know if tests passed or not, but if there was an error
- // during testing we don't want to just suceeed (we may not have
+ // during testing we don't want to just succeed (we may not have
// tested something), so fail.
//
// This should realistically "never" happen, so don't try to make
format!("{:x}", hash.finish())
}
+#[derive(Copy, Clone)]
struct TestCx<'test> {
config: &'test Config,
props: &'test TestProps,
script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path
- script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path));
+ script_str
+ .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\")));
// Load the target executable
script_str
self.config.target.contains("vxworks") && !self.is_vxworks_pure_static()
}
- fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
+ fn build_all_auxiliary(&self, rustc: &mut Command) -> PathBuf {
let aux_dir = self.aux_output_dir_name();
if !self.props.aux_builds.is_empty() {
rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
}
+ aux_dir
+ }
+
+ fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
+ let aux_dir = self.build_all_auxiliary(&mut rustc);
self.props.unset_rustc_env.clone().iter().fold(&mut rustc, |rustc, v| rustc.env_remove(v));
rustc.envs(self.props.rustc_env.clone());
self.compose_and_run(
let (dylib, crate_type) = if aux_props.no_prefer_dynamic {
(true, None)
- } else if self.config.target.contains("cloudabi")
- || self.config.target.contains("emscripten")
+ } else if self.config.target.contains("emscripten")
|| (self.config.target.contains("musl")
&& !aux_props.force_host
&& !self.config.host.contains("musl"))
fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! {
self.error(err);
- proc_res.fatal(None);
+ proc_res.fatal(None, || ());
+ }
+
+ fn fatal_proc_rec_with_ctx(
+ &self,
+ err: &str,
+ proc_res: &ProcRes,
+ on_failure: impl FnOnce(Self),
+ ) -> ! {
+ self.error(err);
+ proc_res.fatal(None, || on_failure(*self));
}
// codegen tests (using FileCheck)
let res = self.cmd2procres(
Command::new(&self.config.docck_python)
.arg(root.join("src/etc/htmldocck.py"))
- .arg(out_dir)
+ .arg(&out_dir)
.arg(&self.testpaths.file),
);
if !res.status.success() {
- self.fatal_proc_rec("htmldocck failed!", &res);
+ self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| {
+ this.compare_to_default_rustdoc(&out_dir)
+ });
}
}
}
+ fn compare_to_default_rustdoc(&mut self, out_dir: &Path) {
+ println!("info: generating a diff against nightly rustdoc");
+
+ let suffix =
+ self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly");
+ let compare_dir = output_base_dir(self.config, self.testpaths, Some(&suffix));
+ // Don't give an error if the directory didn't already exist
+ let _ = fs::remove_dir_all(&compare_dir);
+ create_dir_all(&compare_dir).unwrap();
+
+ // We need to create a new struct for the lifetimes on `config` to work.
+ let new_rustdoc = TestCx {
+ config: &Config {
+ // FIXME: use beta or a user-specified rustdoc instead of
+ // hardcoding the default toolchain
+ rustdoc_path: Some("rustdoc".into()),
+ // Needed for building auxiliary docs below
+ rustc_path: "rustc".into(),
+ ..self.config.clone()
+ },
+ ..*self
+ };
+
+ let output_file = TargetLocation::ThisDirectory(new_rustdoc.aux_output_dir_name());
+ let mut rustc = new_rustdoc.make_compile_args(
+ &new_rustdoc.testpaths.file,
+ output_file,
+ EmitMetadata::No,
+ AllowUnused::Yes,
+ );
+ rustc.arg("-L").arg(&new_rustdoc.aux_output_dir_name());
+ new_rustdoc.build_all_auxiliary(&mut rustc);
+
+ let proc_res = new_rustdoc.document(&compare_dir);
+ if !proc_res.status.success() {
+ proc_res.fatal(Some("failed to run nightly rustdoc"), || ());
+ }
+
+ #[rustfmt::skip]
+ let tidy_args = [
+ "--indent", "yes",
+ "--indent-spaces", "2",
+ "--wrap", "0",
+ "--show-warnings", "no",
+ "--markup", "yes",
+ "--quiet", "yes",
+ "-modify",
+ ];
+ let tidy_dir = |dir| {
+ let tidy = |file: &_| {
+ Command::new("tidy")
+ .args(&tidy_args)
+ .arg(file)
+ .spawn()
+ .unwrap_or_else(|err| {
+ self.fatal(&format!("failed to run tidy - is it installed? - {}", err))
+ })
+ .wait()
+ .unwrap()
+ };
+ for entry in walkdir::WalkDir::new(dir) {
+ let entry = entry.expect("failed to read file");
+ if entry.file_type().is_file()
+ && entry.path().extension().and_then(|p| p.to_str()) == Some("html".into())
+ {
+ tidy(entry.path());
+ }
+ }
+ };
+ tidy_dir(out_dir);
+ tidy_dir(&compare_dir);
+
+ let pager = {
+ let output = Command::new("git").args(&["config", "--get", "core.pager"]).output().ok();
+ output.and_then(|out| {
+ if out.status.success() {
+ Some(String::from_utf8(out.stdout).expect("invalid UTF8 in git pager"))
+ } else {
+ None
+ }
+ })
+ };
+ let mut diff = Command::new("diff");
+ diff.args(&["-u", "-r"]).args(&[out_dir, &compare_dir]);
+
+ let output = if let Some(pager) = pager {
+ let diff_pid = diff.stdout(Stdio::piped()).spawn().expect("failed to run `diff`");
+ let pager = pager.trim();
+ if self.config.verbose {
+ eprintln!("using pager {}", pager);
+ }
+ let output = Command::new(pager)
+ // disable paging; we want this to be non-interactive
+ .env("PAGER", "")
+ .stdin(diff_pid.stdout.unwrap())
+ // Capture output and print it explicitly so it will in turn be
+ // captured by libtest.
+ .output()
+ .unwrap();
+ assert!(output.status.success());
+ output
+ } else {
+ eprintln!("warning: no pager configured, falling back to `diff --color`");
+ eprintln!(
+ "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`"
+ );
+ let output = diff.arg("--color").output().unwrap();
+ assert!(output.status.success() || output.status.code() == Some(1));
+ output
+ };
+ println!("{}", String::from_utf8_lossy(&output.stdout));
+ eprintln!("{}", String::from_utf8_lossy(&output.stderr));
+ }
+
fn get_lines<P: AsRef<Path>>(
&self,
path: &P,
}
impl ProcRes {
- pub fn fatal(&self, err: Option<&str>) -> ! {
+ pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! {
if let Some(e) = err {
println!("\nerror: {}", e);
}
json::extract_rendered(&self.stdout),
json::extract_rendered(&self.stderr),
);
+ on_failure();
// Use resume_unwind instead of panic!() to prevent a panic message + backtrace from
// compiletest, which is unnecessary noise.
std::panic::resume_unwind(Box::new(()));
const OS_TABLE: &[(&str, &str)] = &[
("android", "android"),
("androideabi", "android"),
- ("cloudabi", "cloudabi"),
("cuda", "cuda"),
("darwin", "macos"),
("dragonfly", "dragonfly"),
-Subproject commit df4109151b6870cdb6d170326d1c099746990ea8
+Subproject commit 746ea5b141baf1f86c2ad17753a37b135e0c1aa3
// parser to tidy.
!file.ancestors().any(|a| {
a.ends_with("src/test") ||
- a.ends_with("library/std/src/sys/cloudabi") ||
a.ends_with("src/doc/book")
});
// UI tests with different names
|| path.ends_with("src/thread/local/dynamic_tests.rs")
|| path.ends_with("src/sync/mpsc/sync_tests.rs")
- // Has copyright banner
- || path.ends_with("src/sys/cloudabi/abi/cloudabi.rs")
}
};