diff --git a/RELEASES.md b/RELEASES.md index 9fd796fd775bf..8f04980e39036 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,131 @@ +Version 1.49.0 (2020-12-31) +============================ + +Language +----------------------- + +- [Unions can now implement `Drop`, and you can now have a field in a union + with `ManuallyDrop`.][77547] +- [You can now cast uninhabited enums to integers.][76199] +- [You can now bind by reference and by move in patterns.][76119] This + allows you to selectively borrow individual components of a type. E.g. + ```rust + #[derive(Debug)] + struct Person { + name: String, + age: u8, + } + + let person = Person { + name: String::from("Alice"), + age: 20, + }; + + // `name` is moved out of person, but `age` is referenced. + let Person { name, ref age } = person; + println!("{} {}", name, age); + ``` + +Compiler +----------------------- + +- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228] +- [Added tier 2 support for `aarch64-apple-darwin`.][75991] +- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914] +- [Added tier 3 support for `mipsel-unknown-none`.][78676] +- [Raised the minimum supported LLVM version to LLVM 9.][78848] +- [Output from threads spawned in tests is now captured.][78227] +- [Change os and vendor values to "none" and "unknown" for some targets][78951] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +----------------------- + +- [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109] +- [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997] +- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989] + +Stabilized APIs +--------------- + +- [`slice::select_nth_unstable`] +- [`slice::select_nth_unstable_by`] +- [`slice::select_nth_unstable_by_key`] + +The following previously stable methods are now `const`. + +- [`Poll::is_ready`] +- [`Poll::is_pending`] + +Cargo +----------------------- +- [Building a crate with `cargo-package` should now be independently reproducible.][cargo/8864] +- [`cargo-tree` now marks proc-macro crates.][cargo/8765] +- [Added `CARGO_PRIMARY_PACKAGE` build-time environment variable.][cargo/8758] This + variable will be set if the crate being built is one the user selected to build, either + with `-p` or through defaults. +- [You can now use glob patterns when specifying packages & targets.][cargo/8752] + + +Compatibility Notes +------------------- + +- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier 2 support.][78746] +- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376] +- [Rustc will now check for the validity of some built-in attributes on enum variants.][77015] + Previously such invalid or unused attributes could be ignored. +- Leading whitespace is stripped more uniformly in documentation comments, which may change behavior. You + read [this post about the changes][rustdoc-ws-post] for more details. +- [Trait bounds are no longer inferred for associated types.][79904] + +Internal Only +------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc and +related tools. + +- [rustc's internal crates are now compiled using the `initial-exec` Thread + Local Storage model.][78201] +- [Calculate visibilities once in resolve.][78077] +- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703] +- [Added `--color` for configuring terminal color support to bootstrap.][79004] + + +[75991]: https://github.com/rust-lang/rust/pull/75991 +[78951]: https://github.com/rust-lang/rust/pull/78951 +[78848]: https://github.com/rust-lang/rust/pull/78848 +[78746]: https://github.com/rust-lang/rust/pull/78746 +[78376]: https://github.com/rust-lang/rust/pull/78376 +[78228]: https://github.com/rust-lang/rust/pull/78228 +[78227]: https://github.com/rust-lang/rust/pull/78227 +[78201]: https://github.com/rust-lang/rust/pull/78201 +[78109]: https://github.com/rust-lang/rust/pull/78109 +[78077]: https://github.com/rust-lang/rust/pull/78077 +[77997]: https://github.com/rust-lang/rust/pull/77997 +[77703]: https://github.com/rust-lang/rust/pull/77703 +[77547]: https://github.com/rust-lang/rust/pull/77547 +[77015]: https://github.com/rust-lang/rust/pull/77015 +[76199]: https://github.com/rust-lang/rust/pull/76199 +[76119]: https://github.com/rust-lang/rust/pull/76119 +[75914]: https://github.com/rust-lang/rust/pull/75914 +[74989]: https://github.com/rust-lang/rust/pull/74989 +[79004]: https://github.com/rust-lang/rust/pull/79004 +[78676]: https://github.com/rust-lang/rust/pull/78676 +[79904]: https://github.com/rust-lang/rust/issues/79904 +[cargo/8864]: https://github.com/rust-lang/cargo/pull/8864 +[cargo/8765]: https://github.com/rust-lang/cargo/pull/8765 +[cargo/8758]: https://github.com/rust-lang/cargo/pull/8758 +[cargo/8752]: https://github.com/rust-lang/cargo/pull/8752 +[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable +[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by +[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key +[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html +[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready +[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending +[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc + Version 1.48.0 (2020-11-19) ========================== @@ -10,7 +138,7 @@ Language Compiler -------- - [Stabilised the `-C link-self-contained=` compiler flag.][76158] This tells - `rustc` whether to link its own C runtime and libraries or to rely on a external + `rustc` whether to link its own C runtime and libraries or to rely on a external linker to find them. (Supported only on `windows-gnu`, `linux-musl`, and `wasi` platforms.) - [You can now use `-C target-feature=+crt-static` on `linux-gnu` targets.][77386] Note: If you're using cargo you must explicitly pass the `--target` flag. @@ -82,7 +210,7 @@ Compatibility Notes - [Foreign exceptions are now caught by `catch_unwind` and will cause an abort.][70212] Note: This behaviour is not guaranteed and is still considered undefined behaviour, see the [`catch_unwind`] documentation for further information. - + Internal Only @@ -102,7 +230,7 @@ related tools. [76030]: https://github.com/rust-lang/rust/pull/76030/ [70212]: https://github.com/rust-lang/rust/pull/70212/ [27675]: https://github.com/rust-lang/rust/issues/27675/ -[54121]: https://github.com/rust-lang/rust/issues/54121/ +[54121]: https://github.com/rust-lang/rust/issues/54121/ [71274]: https://github.com/rust-lang/rust/pull/71274/ [77386]: https://github.com/rust-lang/rust/pull/77386/ [77153]: https://github.com/rust-lang/rust/pull/77153/ diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 45cc6d894e9e8..b0d243985751a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -167,10 +167,7 @@ pub enum GenericArgs { impl GenericArgs { pub fn is_angle_bracketed(&self) -> bool { - match *self { - AngleBracketed(..) => true, - _ => false, - } + matches!(self, AngleBracketed(..)) } pub fn span(&self) -> Span { @@ -629,10 +626,7 @@ impl Pat { /// Is this a `..` pattern? pub fn is_rest(&self) -> bool { - match self.kind { - PatKind::Rest => true, - _ => false, - } + matches!(self.kind, PatKind::Rest) } } @@ -852,10 +846,7 @@ impl BinOpKind { } } pub fn lazy(&self) -> bool { - match *self { - BinOpKind::And | BinOpKind::Or => true, - _ => false, - } + matches!(self, BinOpKind::And | BinOpKind::Or) } pub fn is_comparison(&self) -> bool { @@ -963,17 +954,11 @@ impl Stmt { } pub fn is_item(&self) -> bool { - match self.kind { - StmtKind::Item(_) => true, - _ => false, - } + matches!(self.kind, StmtKind::Item(_)) } pub fn is_expr(&self) -> bool { - match self.kind { - StmtKind::Expr(_) => true, - _ => false, - } + matches!(self.kind, StmtKind::Expr(_)) } } @@ -1652,26 +1637,17 @@ pub enum LitKind { impl LitKind { /// Returns `true` if this literal is a string. pub fn is_str(&self) -> bool { - match *self { - LitKind::Str(..) => true, - _ => false, - } + matches!(self, LitKind::Str(..)) } /// Returns `true` if this literal is byte literal string. pub fn is_bytestr(&self) -> bool { - match self { - LitKind::ByteStr(_) => true, - _ => false, - } + matches!(self, LitKind::ByteStr(_)) } /// Returns `true` if this is a numeric literal. pub fn is_numeric(&self) -> bool { - match *self { - LitKind::Int(..) | LitKind::Float(..) => true, - _ => false, - } + matches!(self, LitKind::Int(..) | LitKind::Float(..)) } /// Returns `true` if this literal has no suffix. @@ -2237,10 +2213,7 @@ impl FnDecl { self.inputs.get(0).map_or(false, Param::is_self) } pub fn c_variadic(&self) -> bool { - self.inputs.last().map_or(false, |arg| match arg.ty.kind { - TyKind::CVarArgs => true, - _ => false, - }) + self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs)) } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 19c7c479f0429..726ae5e51f7a6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -234,10 +234,7 @@ impl MetaItem { } pub fn is_word(&self) -> bool { - match self.kind { - MetaItemKind::Word => true, - _ => false, - } + matches!(self.kind, MetaItemKind::Word) } pub fn has_name(&self, name: Symbol) -> bool { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index a74464937c8b4..cd1e444bcf72a 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -130,10 +130,7 @@ impl LitKind { } crate fn may_have_suffix(self) -> bool { - match self { - Integer | Float | Err => true, - _ => false, - } + matches!(self, Integer | Float | Err) } } @@ -305,10 +302,7 @@ impl TokenKind { } pub fn should_end_const_arg(&self) -> bool { - match self { - Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true, - _ => false, - } + matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr)) } } @@ -346,18 +340,21 @@ impl Token { } pub fn is_op(&self) -> bool { - match self.kind { - OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | Eof => false, - _ => true, - } + !matches!( + self.kind, + OpenDelim(..) + | CloseDelim(..) + | Literal(..) + | DocComment(..) + | Ident(..) + | Lifetime(..) + | Interpolated(..) + | Eof + ) } pub fn is_like_plus(&self) -> bool { - match self.kind { - BinOp(Plus) | BinOpEq(Plus) => true, - _ => false, - } + matches!(self.kind, BinOp(Plus) | BinOpEq(Plus)) } /// Returns `true` if the token can appear at the start of an expression. @@ -379,13 +376,10 @@ impl Token { ModSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => match **nt { - NtLiteral(..) | + Interpolated(ref nt) => matches!(**nt, NtLiteral(..) | NtExpr(..) | NtBlock(..) | - NtPath(..) => true, - _ => false, - }, + NtPath(..)), _ => false, } } @@ -405,10 +399,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path ModSep => true, // global path - Interpolated(ref nt) => match **nt { - NtTy(..) | NtPath(..) => true, - _ => false, - }, + Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)), _ => false, } } @@ -417,10 +408,7 @@ impl Token { pub fn can_begin_const_arg(&self) -> bool { match self.kind { OpenDelim(Brace) => true, - Interpolated(ref nt) => match **nt { - NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, - _ => false, - }, + Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), _ => self.can_begin_literal_maybe_minus(), } } @@ -436,10 +424,7 @@ impl Token { /// Returns `true` if the token is any literal. pub fn is_lit(&self) -> bool { - match self.kind { - Literal(..) => true, - _ => false, - } + matches!(self.kind, Literal(..)) } /// Returns `true` if the token is any literal, a minus (which can prefix a literal, diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 60422a2e57392..90786520fe802 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -12,14 +12,14 @@ use crate::ast; /// |x| 5 /// isn't parsed as (if true {...} else {...} | x) | 5 pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - match e.kind { + !matches!( + e.kind, ast::ExprKind::If(..) - | ast::ExprKind::Match(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::While(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop(..) - | ast::ExprKind::TryBlock(..) => false, - _ => true, - } + | ast::ExprKind::Match(..) + | ast::ExprKind::Block(..) + | ast::ExprKind::While(..) + | ast::ExprKind::Loop(..) + | ast::ExprKind::ForLoop(..) + | ast::ExprKind::TryBlock(..) + ) } diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index 5d994c903795b..542a330a03141 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -180,10 +180,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { if doc_style.is_none() { - let code_to_the_right = match text[pos + token.len..].chars().next() { - Some('\r' | '\n') => false, - _ => true, - }; + let code_to_the_right = + !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n')); let style = match (code_to_the_left, code_to_the_right) { (_, true) => CommentStyle::Mixed, (false, false) => CommentStyle::Isolated, diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 957c8035399a2..ca1226b445d97 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -38,10 +38,9 @@ pub fn expand_deriving_clone( | ItemKind::Enum(_, Generics { ref params, .. }) => { let container_id = cx.current_expansion.id.expn_data().parent; if cx.resolver.has_derive_copy(container_id) - && !params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) { bounds = vec![]; is_shallow = true; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6531e68be9cdc..e78d1368b357e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -404,12 +404,10 @@ impl<'a> TraitDef<'a> { let has_no_type_params = match item.kind { ast::ItemKind::Struct(_, ref generics) | ast::ItemKind::Enum(_, ref generics) - | ast::ItemKind::Union(_, ref generics) => { - !generics.params.iter().any(|param| match param.kind { - ast::GenericParamKind::Type { .. } => true, - _ => false, - }) - } + | ast::ItemKind::Union(_, ref generics) => !generics + .params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), _ => unreachable!(), }; let container_id = cx.current_expansion.id.expn_data().parent; @@ -868,7 +866,7 @@ impl<'a> MethodDef<'a> { Self_ if nonstatic => { self_args.push(arg_expr); } - Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => { + Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => { self_args.push(cx.expr_deref(trait_.span, arg_expr)) } _ => { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 550524e652af7..85ca1da6f1daa 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1044,10 +1044,7 @@ pub fn expand_preparsed_format_args( let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg { parse::String(_) => false, - parse::NextArgument(arg) => match arg.position { - parse::Position::ArgumentIs(_) => true, - _ => false, - }, + parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)), }); cx.build_index_map(); diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index f00dfd1241fbb..0496c72cb0050 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -580,10 +580,7 @@ pub mod printf { } fn is_flag(c: &char) -> bool { - match c { - '0' | '-' | '+' | ' ' | '#' | '\'' => true, - _ => false, - } + matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'') } #[cfg(test)] diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs index db73fdbe24ff5..d203b5bc5429e 100644 --- a/compiler/rustc_builtin_macros/src/llvm_asm.rs +++ b/compiler/rustc_builtin_macros/src/llvm_asm.rs @@ -87,9 +87,11 @@ fn parse_inline_asm<'a>( // parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription. let first_colon = tts .trees() - .position(|tt| match tt { - tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) => true, - _ => false, + .position(|tt| { + matches!( + tt, + tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) + ) }) .unwrap_or(tts.len()); let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect()); diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 4e91436199a53..7582d9805390e 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -256,10 +256,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // we're just not interested in this item. // // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. - let is_fn = match item.kind { - ast::ItemKind::Fn(..) => true, - _ => false, - }; + let is_fn = matches!(item.kind, ast::ItemKind::Fn(..)); let mut found_attr: Option<&'a ast::Attribute> = None; diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 44bb0deeae97f..57e49ba8d1a56 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -112,12 +112,12 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { }; // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = match context { + let is_consume = matches!( + context, PlaceContext::NonMutatingUse( NonMutatingUseContext::Copy | NonMutatingUseContext::Move, - ) => true, - _ => false, - }; + ) + ); if is_consume { let base_ty = mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx()); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4d3217a9c0bd9..0958afa03082a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -132,10 +132,7 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { [segment] if segment .res - .map(|res| match res { - Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true, - _ => false, - }) + .map(|res| matches!(res, Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _))) .unwrap_or(false) => { self.types.push(path.span); diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 32f73237dd410..728dc2de37031 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -93,10 +93,7 @@ impl<'tcx> FreeRegionMap<'tcx> { /// True for free regions other than `'static`. pub fn is_free(&self, r: Region<'_>) -> bool { - match *r { - ty::ReEarlyBound(_) | ty::ReFree(_) => true, - _ => false, - } + matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_)) } /// True if `r` is a free region or static of the sort that this diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index d7b2ce7ee2083..ab34cda8cc18f 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -393,10 +393,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { if self.expand_node(a_region, b_vid, b_data) { changes.push(b_vid); } - match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue => false, - _ => true, - } + !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue) }); } } @@ -972,11 +969,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } VerifyBound::IsEmpty => { - if let ty::ReEmpty(_) = min { - true - } else { - false - } + matches!(min, ty::ReEmpty(_)) } VerifyBound::AnyBound(bs) => { diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs index 6f572a4875f86..9d392c7b26bf7 100644 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ b/compiler/rustc_middle/src/hir/map/blocks.rs @@ -42,37 +42,25 @@ trait MaybeFnLike { impl MaybeFnLike for hir::Item<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ItemKind::Fn(..)) } } impl MaybeFnLike for hir::ImplItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ImplItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ImplItemKind::Fn(..)) } } impl MaybeFnLike for hir::TraitItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true, - _ => false, - } + matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) } } impl MaybeFnLike for hir::Expr<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ExprKind::Closure(..) => true, - _ => false, - } + matches!(self.kind, hir::ExprKind::Closure(..)) } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 8a6bf9dff7b6f..95096d0fb719c 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -118,17 +118,11 @@ impl CoverageKind { } pub fn is_counter(&self) -> bool { - match self { - Self::Counter { .. } => true, - _ => false, - } + matches!(self, Self::Counter { .. }) } pub fn is_expression(&self) -> bool { - match self { - Self::Expression { .. } => true, - _ => false, - } + matches!(self, Self::Expression { .. }) } pub fn is_unreachable(&self) -> bool { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1b5f7a2c12e72..1e836d0a84253 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -576,11 +576,13 @@ rustc_queries! { desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } } - query impl_trait_ref(key: DefId) -> Option> { - desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) } + /// Given an `impl_id`, return the trait it implements. + /// Return `None` if this is an inherent impl. + query impl_trait_ref(impl_id: DefId) -> Option> { + desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } } - query impl_polarity(key: DefId) -> ty::ImplPolarity { - desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) } + query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { + desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } } query issue33140_self_ty(key: DefId) -> Option> { @@ -917,8 +919,10 @@ rustc_queries! { } TypeChecking { - query trait_of_item(def_id: DefId) -> Option { - desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) } + /// Given an `associated_item`, find the trait it belongs to. + /// Return `None` if the `DefId` is not an associated item. + query trait_of_item(associated_item: DefId) -> Option { + desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) } } } @@ -948,20 +952,29 @@ rustc_queries! { } TypeChecking { - query all_local_trait_impls(key: CrateNum) -> &'tcx BTreeMap> { + /// Return all `impl` blocks in the current crate. + /// + /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number. + /// Passing in any other crate will cause an ICE. + /// + /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE + query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap> { desc { "local trait impls" } } - query trait_impls_of(key: DefId) -> ty::trait_def::TraitImpls { + + /// Given a trait `trait_id`, return all known `impl` blocks. + query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls { storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) } + desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) } } - query specialization_graph_of(key: DefId) -> specialization_graph::Graph { + + query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph { storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) } + desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } } - query object_safety_violations(key: DefId) -> &'tcx [traits::ObjectSafetyViolation] { - desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } + query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { + desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) } } /// Gets the ParameterEnvironment for a given item; this environment @@ -969,6 +982,7 @@ rustc_queries! { /// type-checking etc, and it does not normalize specializable /// associated types. This is almost always what you want, /// unless you are doing MIR optimizations, in which case you + /// might want to use `reveal_all()` method to change modes. query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } } @@ -1229,10 +1243,15 @@ rustc_queries! { } TypeChecking { + /// Given a crate and a trait, look up all impls of that trait in the crate. + /// Return `(impl_id, self_ty)`. query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option)] { desc { "looking up implementations of a trait in a crate" } } + + /// Given a crate, look up all trait impls in that crate. + /// Return `(impl_id, self_ty)`. query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option)] { desc { "looking up all (?) trait implementations" } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index fc02e78b2fadf..fe20925b38798 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -647,14 +647,11 @@ impl Trait for X { let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. - let callable_scope = match body_owner { - Some( + let callable_scope = matches!(body_owner, Some( hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), - ) => true, - _ => false, - }; + )); let impl_comparison = matches!( cause_code, ObligationCauseCode::CompareImplMethodObligation { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1f70fdb5ae30b..09281799041ee 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -40,11 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_span = expr.span; let source_info = this.source_info(expr_span); - let expr_is_block_or_scope = match expr.kind { - ExprKind::Block { .. } => true, - ExprKind::Scope { .. } => true, - _ => false, - }; + let expr_is_block_or_scope = matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. }); let schedule_drop = move |this: &mut Self| { if let Some(drop_scope) = scope { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4510e86e0341f..60a47ca12b868 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -501,10 +501,9 @@ impl<'a> Parser<'a> { pub(super) fn expr_is_valid_const_arg(&self, expr: &P) -> bool { match &expr.kind { ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true, - ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind { - ast::ExprKind::Lit(_) => true, - _ => false, - }, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) => { + matches!(expr.kind, ast::ExprKind::Lit(_)) + } // We can only resolve single-segment paths at the moment, because multi-segment paths // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`. ast::ExprKind::Path(None, path) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 00152878d6d9b..c4fb0cf5b28dc 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -23,18 +23,18 @@ use rustc_span::symbol::{sym, Symbol}; // function, then we should explore its block to check for codes that // may need to be marked as live. fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { - match tcx.hir().find(hir_id) { + matches!( + tcx.hir().find(hir_id), Some( Node::Item(..) - | Node::ImplItem(..) - | Node::ForeignItem(..) - | Node::TraitItem(..) - | Node::Variant(..) - | Node::AnonConst(..) - | Node::Pat(..), - ) => true, - _ => false, - } + | Node::ImplItem(..) + | Node::ForeignItem(..) + | Node::TraitItem(..) + | Node::Variant(..) + | Node::AnonConst(..) + | Node::Pat(..), + ) + ) } struct MarkSymbolVisitor<'tcx> { @@ -500,16 +500,16 @@ struct DeadVisitor<'tcx> { impl DeadVisitor<'tcx> { fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool { - let should_warn = match item.kind { + let should_warn = matches!( + item.kind, hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) => true, - _ => false, - }; + | hir::ItemKind::Const(..) + | hir::ItemKind::Fn(..) + | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) + ); should_warn && !self.symbol_is_live(item.hir_id) } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 86ce35c6d9909..54e3cc69aea9a 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -367,10 +367,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - let is_shorthand = match param.pat.kind { - rustc_hir::PatKind::Struct(..) => true, - _ => false, - }; + let is_shorthand = matches!(param.pat.kind, rustc_hir::PatKind::Struct(..)); param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = if is_shorthand { Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true }) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 3b4249a93e1fb..708563f2ee981 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -842,11 +842,9 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { let macro_module_def_id = ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id()) .unwrap(); - // FIXME(#71104) Should really be using just `as_local_hir_id` but - // some `DefId` do not seem to have a corresponding HirId. let hir_id = macro_module_def_id .as_local() - .and_then(|def_id| self.tcx.hir().opt_local_def_id_to_hir_id(def_id)); + .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)); let mut module_id = match hir_id { Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id, // `module_id` doesn't correspond to a `mod`, return early (#63164, #65252). diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d253a9dda861b..7d8f112af8a51 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1653,17 +1653,14 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { for missing in &self.missing_named_lifetime_spots { match missing { MissingLifetimeSpot::Generics(generics) => { - let (span, sugg) = if let Some(param) = - generics.params.iter().find(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Elided, - } => false, - _ => true, - }) { + let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| { + !matches!(p.kind, hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } | hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Elided, + }) + }) { (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) } else { suggests_in_band = true; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6ab16886ed237..fc6a9a7f20972 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -35,10 +35,7 @@ pub enum AutoTraitResult { #[allow(dead_code)] impl AutoTraitResult { fn is_auto(&self) -> bool { - match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, - _ => false, - } + matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl) } } @@ -601,10 +598,7 @@ impl AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match *p.ty().skip_binder().kind() { - ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, - _ => false, - } + matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty) } fn evaluate_nested_obligations( diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9324d55ac1b2d..99b96f6096476 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -193,10 +193,8 @@ fn overlap_within_probe( let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) { - Some(true) => true, - _ => false, - }; + let involves_placeholder = + matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true)); Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9feba7bfc492f..1d82e732907ba 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -861,10 +861,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { let arg_length = arguments.len(); - let distinct = match &other[..] { - &[ArgKind::Tuple(..)] => true, - _ => false, - }; + let distinct = matches!(other, &[ArgKind::Tuple(..)]); match (arg_length, arguments.get(0)) { (1, Some(&ArgKind::Tuple(_, ref fields))) => { format!("a single {}-tuple as argument", fields.len()) @@ -1201,12 +1198,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { normalized_ty, data.ty ); - let is_normalized_ty_expected = match &obligation.cause.code { - ObligationCauseCode::ItemObligation(_) + let is_normalized_ty_expected = !matches!(obligation.cause.code, ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) => false, - _ => true, - }; + | ObligationCauseCode::ObjectCastObligation(_)); if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( is_normalized_ty_expected, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2fb9b3cd5d305..9c894e99a389a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -323,9 +323,8 @@ pub fn normalize_param_env_or_error<'tcx>( // This works fairly well because trait matching does not actually care about param-env // TypeOutlives predicates - these are normally used by regionck. let outlives_predicates: Vec<_> = predicates - .drain_filter(|predicate| match predicate.skip_binders() { - ty::PredicateAtom::TypeOutlives(..) => true, - _ => false, + .drain_filter(|predicate| { + matches!(predicate.skip_binders(), ty::PredicateAtom::TypeOutlives(..)) }) .collect(); diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index f3a55fec9e462..bd2f87f70a2f1 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -98,7 +98,7 @@ crate fn evaluate_goal<'tcx>( let mut solver = chalk_engine::solve::SLGSolver::new(32, None); let db = ChalkRustIrDatabase { interner, reempty_placeholder }; let solution = solver.solve(&db, &lowered_goal); - debug!(?obligation, ?solution, "evaluatate goal"); + debug!(?obligation, ?solution, "evaluate goal"); // Ideally, the code to convert *back* to rustc types would live close to // the code to convert *from* rustc types. Right now though, we don't diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index b7e77f389f857..0feac036f0026 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -526,18 +526,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generics: &ty::Generics, ) -> bool { let explicit = !seg.infer_args; - let impl_trait = - generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: - Some( - hir::SyntheticTyParamKind::ImplTrait - | hir::SyntheticTyParamKind::FromAttr, - ), - .. - } => true, - _ => false, - }); + let impl_trait = generics.params.iter().any(|param| { + matches!(param.kind, ty::GenericParamDefKind::Type { + synthetic: + Some( + hir::SyntheticTyParamKind::ImplTrait + | hir::SyntheticTyParamKind::FromAttr, + ), + .. + }) + }); if explicit && impl_trait { let spans = seg diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index ec7369fd3e8ee..9c60e8933d4db 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -543,10 +543,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let Some(ty) = prohibit_opaque.break_value() { let is_async = match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { - hir::OpaqueTyOrigin::AsyncFn => true, - _ => false, - }, + ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + matches!(origin, hir::OpaqueTyOrigin::AsyncFn) + } _ => unreachable!(), }; @@ -1321,10 +1320,7 @@ pub fn check_enum<'tcx>( } if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { - let is_unit = |var: &hir::Variant<'_>| match var.data { - hir::VariantData::Unit(..) => true, - _ => false, - }; + let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); let has_non_units = vs.iter().any(|var| !is_unit(var)); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 333bda00dbe81..3e60924d6fcf8 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -325,10 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); } - let is_closure = match arg.kind { - ExprKind::Closure(..) => true, - _ => false, - }; + let is_closure = matches!(arg.kind, ExprKind::Closure(..)); if is_closure != check_closures { continue; diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index b8b98cef7637a..eca6ce1ecdb63 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -354,10 +354,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { hir_id: hir::HirId, ) { assert!( - match fk { - intravisit::FnKind::Closure(..) => true, - _ => false, - }, + matches!(fk, intravisit::FnKind::Closure(..)), "visit_fn invoked for something other than a closure" ); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index dd4bfc7a75115..29b03d118e25a 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -156,10 +156,10 @@ crate fn placeholder_type_error( if let Some(span) = span { sugg.push((span, format!("<{}>", type_name))); } - } else if let Some(arg) = generics.iter().find(|arg| match arg.name { - hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true, - _ => false, - }) { + } else if let Some(arg) = generics + .iter() + .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))) + { // Account for `_` already present in cases like `struct S<_>(_);` and suggest // `struct S(T);` instead of `struct S<_, T>(T);`. sugg.push((arg.span, (*type_name).to_string())); @@ -1544,12 +1544,27 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let mut diag = bad_placeholder_type(tcx, visitor.0); let ret_ty = fn_sig.output(); if ret_ty != tcx.ty_error() { - diag.span_suggestion( - ty.span, - "replace with the correct return type", - ret_ty.to_string(), - Applicability::MaybeIncorrect, - ); + if !ret_ty.is_closure() { + let ret_ty_str = match ret_ty.kind() { + // Suggest a function pointer return type instead of a unique function definition + // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid + // syntax) + ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(), + _ => ret_ty.to_string(), + }; + diag.span_suggestion( + ty.span, + "replace with the correct return type", + ret_ty_str, + Applicability::MaybeIncorrect, + ); + } else { + // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds + // to prevent the user from getting a papercut while trying to use the unique closure + // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`). + diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); + diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html"); + } } diag.emit(); ty::Binder::bind(fn_sig) diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index ce9fd5575cf95..3ce244e11bf45 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -595,10 +595,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let upvars = self.tcx().upvars_mentioned(self.body_owner); // For purposes of this function, generator and closures are equivalent. - let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() { - ty::Closure(..) | ty::Generator(..) => true, - _ => false, - }; + let body_owner_is_closure = matches!( + self.tcx().type_of(self.body_owner.to_def_id()).kind(), + ty::Closure(..) | ty::Generator(..) + ); if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) { diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 9c53c84f5b2fb..1d6488dd2dfe3 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -81,15 +81,18 @@ impl Root { // the appended elements even if advancing the iterator panicks. *length += 1; } - self.fix_right_edge(); + self.fix_right_border_of_plentiful(); } - fn fix_right_edge(&mut self) { - // Handle underfull nodes, start from the top. + /// Stock up any underfull nodes on the right border of the tree. + /// The other nodes, those that are not the root nor a rightmost edge, + /// must have MIN_LEN elements to spare. + fn fix_right_border_of_plentiful(&mut self) { let mut cur_node = self.borrow_mut(); while let Internal(internal) = cur_node.force() { // Check if right-most child is underfull. let mut last_kv = internal.last_kv().consider_for_balancing(); + debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2); let right_child_len = last_kv.right_child_len(); if right_child_len < MIN_LEN { // We need to steal. diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 26f8f9da7ec82..f92aed8ce15bf 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1821,7 +1821,6 @@ fn test_append_ord_chaos() { } fn rand_data(len: usize) -> Vec<(u32, u32)> { - assert!(len * 2 <= 70029); // from that point on numbers repeat let mut rng = DeterministicRng::new(); Vec::from_iter((0..len).map(|_| (rng.next(), rng.next()))) } @@ -1886,6 +1885,25 @@ fn test_split_off_tiny_right_height_2() { assert_eq!(*right.last_key_value().unwrap().0, last); } +#[test] +fn test_split_off_halfway() { + let mut rng = DeterministicRng::new(); + for &len in &[NODE_CAPACITY, 25, 50, 75, 100] { + let mut data = Vec::from_iter((0..len).map(|_| (rng.next(), ()))); + // Insertion in non-ascending order creates some variation in node length. + let mut map = BTreeMap::from_iter(data.iter().copied()); + data.sort(); + let small_keys = data.iter().take(len / 2).map(|kv| kv.0); + let large_keys = data.iter().skip(len / 2).map(|kv| kv.0); + let split_key = large_keys.clone().next().unwrap(); + let right = map.split_off(&split_key); + map.check(); + right.check(); + assert!(map.keys().copied().eq(small_keys)); + assert!(right.keys().copied().eq(large_keys)); + } +} + #[test] fn test_split_off_large_random_sorted() { // Miri is too slow diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index ebcbb0e467c46..cdb39104047f0 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -38,6 +38,7 @@ pub unsafe fn unwrap_unchecked(val: Option) -> T { #[cfg(test)] /// XorShiftRng struct DeterministicRng { + count: usize, x: u32, y: u32, z: u32, @@ -47,11 +48,13 @@ struct DeterministicRng { #[cfg(test)] impl DeterministicRng { fn new() -> Self { - DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } + DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } } - /// Guarantees that the first 70029 results are unique. + /// Guarantees that each returned number is unique. fn next(&mut self) -> u32 { + self.count += 1; + assert!(self.count <= 70029); let x = self.x; let t = x ^ (x << 11); self.x = self.y; diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 16b4b1091eff7..b3641a7a0c697 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -489,7 +489,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// /// # Safety /// `index` is in bounds of 0..CAPACITY - unsafe fn key_area_mut_at(&mut self, index: I) -> &mut Output + unsafe fn key_area_mut(&mut self, index: I) -> &mut Output where I: SliceIndex<[MaybeUninit], Output = Output>, { @@ -503,7 +503,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// /// # Safety /// `index` is in bounds of 0..CAPACITY - unsafe fn val_area_mut_at(&mut self, index: I) -> &mut Output + unsafe fn val_area_mut(&mut self, index: I) -> &mut Output where I: SliceIndex<[MaybeUninit], Output = Output>, { @@ -519,7 +519,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { /// /// # Safety /// `index` is in bounds of 0..CAPACITY + 1 - unsafe fn edge_area_mut_at(&mut self, index: I) -> &mut Output + unsafe fn edge_area_mut(&mut self, index: I) -> &mut Output where I: SliceIndex<[MaybeUninit>], Output = Output>, { @@ -583,8 +583,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { assert!(idx < CAPACITY); *len += 1; unsafe { - self.key_area_mut_at(idx).write(key); - self.val_area_mut_at(idx).write(val); + self.key_area_mut(idx).write(key); + self.val_area_mut(idx).write(val); } } @@ -593,8 +593,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { let new_len = self.len() + 1; assert!(new_len <= CAPACITY); unsafe { - slice_insert(self.key_area_mut_at(..new_len), 0, key); - slice_insert(self.val_area_mut_at(..new_len), 0, val); + slice_insert(self.key_area_mut(..new_len), 0, key); + slice_insert(self.val_area_mut(..new_len), 0, val); *self.len_mut() = new_len as u16; } } @@ -627,9 +627,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { assert!(idx < CAPACITY); *len += 1; unsafe { - self.key_area_mut_at(idx).write(key); - self.val_area_mut_at(idx).write(val); - self.edge_area_mut_at(idx + 1).write(edge.node); + self.key_area_mut(idx).write(key); + self.val_area_mut(idx).write(val); + self.edge_area_mut(idx + 1).write(edge.node); Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } @@ -642,9 +642,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { assert!(new_len <= CAPACITY); unsafe { - slice_insert(self.key_area_mut_at(..new_len), 0, key); - slice_insert(self.val_area_mut_at(..new_len), 0, val); - slice_insert(self.edge_area_mut_at(..new_len + 1), 0, edge.node); + slice_insert(self.key_area_mut(..new_len), 0, key); + slice_insert(self.val_area_mut(..new_len), 0, val); + slice_insert(self.edge_area_mut(..new_len + 1), 0, edge.node); *self.len_mut() = new_len as u16; } @@ -662,12 +662,12 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let idx = self.len() - 1; unsafe { - let key = self.key_area_mut_at(idx).assume_init_read(); - let val = self.val_area_mut_at(idx).assume_init_read(); + let key = self.key_area_mut(idx).assume_init_read(); + let val = self.val_area_mut(idx).assume_init_read(); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let node = internal.edge_area_mut_at(idx + 1).assume_init_read(); + let node = internal.edge_area_mut(idx + 1).assume_init_read(); let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; // Currently, clearing the parent link is superfluous, because we will // insert the node elsewhere and set its parent link again. @@ -690,12 +690,12 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let old_len = self.len(); unsafe { - let key = slice_remove(self.key_area_mut_at(..old_len), 0); - let val = slice_remove(self.val_area_mut_at(..old_len), 0); + let key = slice_remove(self.key_area_mut(..old_len), 0); + let val = slice_remove(self.val_area_mut(..old_len), 0); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let node = slice_remove(internal.edge_area_mut_at(..old_len + 1), 0); + let node = slice_remove(internal.edge_area_mut(..old_len + 1), 0); let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; // Currently, clearing the parent link is superfluous, because we will // insert the node elsewhere and set its parent link again. @@ -919,11 +919,11 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark let new_len = self.node.len() + 1; unsafe { - slice_insert(self.node.key_area_mut_at(..new_len), self.idx, key); - slice_insert(self.node.val_area_mut_at(..new_len), self.idx, val); + slice_insert(self.node.key_area_mut(..new_len), self.idx, key); + slice_insert(self.node.val_area_mut(..new_len), self.idx, val); *self.node.len_mut() = new_len as u16; - self.node.val_area_mut_at(self.idx).assume_init_mut() + self.node.val_area_mut(self.idx).assume_init_mut() } } } @@ -978,9 +978,9 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, let new_len = self.node.len() + 1; unsafe { - slice_insert(self.node.key_area_mut_at(..new_len), self.idx, key); - slice_insert(self.node.val_area_mut_at(..new_len), self.idx, val); - slice_insert(self.node.edge_area_mut_at(..new_len + 1), self.idx + 1, edge.node); + slice_insert(self.node.key_area_mut(..new_len), self.idx, key); + slice_insert(self.node.val_area_mut(..new_len), self.idx, val); + slice_insert(self.node.edge_area_mut(..new_len + 1), self.idx + 1, edge.node); *self.node.len_mut() = new_len as u16; self.node.correct_childrens_parent_links(self.idx + 1..new_len + 1); @@ -1085,7 +1085,7 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeTyp impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn key_mut(&mut self) -> &mut K { - unsafe { self.node.key_area_mut_at(self.idx).assume_init_mut() } + unsafe { self.node.key_area_mut(self.idx).assume_init_mut() } } pub fn into_val_mut(self) -> &'a mut V { @@ -1127,16 +1127,16 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> let new_len = self.node.len() - self.idx - 1; new_node.len = new_len as u16; unsafe { - let k = self.node.key_area_mut_at(self.idx).assume_init_read(); - let v = self.node.val_area_mut_at(self.idx).assume_init_read(); + let k = self.node.key_area_mut(self.idx).assume_init_read(); + let v = self.node.val_area_mut(self.idx).assume_init_read(); ptr::copy_nonoverlapping( - self.node.key_area_mut_at(self.idx + 1..).as_ptr(), + self.node.key_area_mut(self.idx + 1..).as_ptr(), new_node.keys.as_mut_ptr(), new_len, ); ptr::copy_nonoverlapping( - self.node.val_area_mut_at(self.idx + 1..).as_ptr(), + self.node.val_area_mut(self.idx + 1..).as_ptr(), new_node.vals.as_mut_ptr(), new_len, ); @@ -1173,8 +1173,8 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { let old_len = self.node.len(); unsafe { - let k = slice_remove(self.node.key_area_mut_at(..old_len), self.idx); - let v = slice_remove(self.node.val_area_mut_at(..old_len), self.idx); + let k = slice_remove(self.node.key_area_mut(..old_len), self.idx); + let v = slice_remove(self.node.val_area_mut(..old_len), self.idx); *self.node.len_mut() = (old_len - 1) as u16; ((k, v), self.left_edge()) } @@ -1195,7 +1195,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, let kv = self.split_leaf_data(&mut new_node.data); let new_len = usize::from(new_node.data.len); ptr::copy_nonoverlapping( - self.node.edge_area_mut_at(self.idx + 1..).as_ptr(), + self.node.edge_area_mut(self.idx + 1..).as_ptr(), new_node.edges.as_mut_ptr(), new_len + 1, ); @@ -1321,25 +1321,23 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { unsafe { *left_node.len_mut() = new_left_len as u16; - let parent_key = - slice_remove(parent_node.key_area_mut_at(..old_parent_len), parent_idx); - left_node.key_area_mut_at(old_left_len).write(parent_key); + let parent_key = slice_remove(parent_node.key_area_mut(..old_parent_len), parent_idx); + left_node.key_area_mut(old_left_len).write(parent_key); ptr::copy_nonoverlapping( - right_node.key_area_mut_at(..).as_ptr(), - left_node.key_area_mut_at(old_left_len + 1..).as_mut_ptr(), + right_node.key_area_mut(..).as_ptr(), + left_node.key_area_mut(old_left_len + 1..).as_mut_ptr(), right_len, ); - let parent_val = - slice_remove(parent_node.val_area_mut_at(..old_parent_len), parent_idx); - left_node.val_area_mut_at(old_left_len).write(parent_val); + let parent_val = slice_remove(parent_node.val_area_mut(..old_parent_len), parent_idx); + left_node.val_area_mut(old_left_len).write(parent_val); ptr::copy_nonoverlapping( - right_node.val_area_mut_at(..).as_ptr(), - left_node.val_area_mut_at(old_left_len + 1..).as_mut_ptr(), + right_node.val_area_mut(..).as_ptr(), + left_node.val_area_mut(old_left_len + 1..).as_mut_ptr(), right_len, ); - slice_remove(&mut parent_node.edge_area_mut_at(..old_parent_len + 1), parent_idx + 1); + slice_remove(&mut parent_node.edge_area_mut(..old_parent_len + 1), parent_idx + 1); parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len); *parent_node.len_mut() -= 1; @@ -1349,8 +1347,8 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { let mut left_node = left_node.reborrow_mut().cast_to_internal_unchecked(); let mut right_node = right_node.cast_to_internal_unchecked(); ptr::copy_nonoverlapping( - right_node.edge_area_mut_at(..).as_ptr(), - left_node.edge_area_mut_at(old_left_len + 1..).as_mut_ptr(), + right_node.edge_area_mut(..).as_ptr(), + left_node.edge_area_mut(old_left_len + 1..).as_mut_ptr(), right_len + 1, ); @@ -1458,7 +1456,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { // Make room for stolen edges. - let right_edges = right.edge_area_mut_at(..).as_mut_ptr(); + let right_edges = right.edge_area_mut(..).as_mut_ptr(); ptr::copy(right_edges, right_edges.add(count), old_right_len + 1); right.correct_childrens_parent_links(count..new_right_len + 1); @@ -1518,7 +1516,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { move_edges(right.reborrow_mut(), 0, left, old_left_len + 1, count); // Fill gap where stolen edges used to be. - let right_edges = right.edge_area_mut_at(..).as_mut_ptr(); + let right_edges = right.edge_area_mut(..).as_mut_ptr(); ptr::copy(right_edges.add(count), right_edges, new_right_len + 1); right.correct_childrens_parent_links(0..=new_right_len); } @@ -1551,8 +1549,8 @@ unsafe fn move_edges<'a, K: 'a, V: 'a>( count: usize, ) { unsafe { - let source_ptr = source.edge_area_mut_at(..).as_ptr(); - let dest_ptr = dest.edge_area_mut_at(dest_offset..).as_mut_ptr(); + let source_ptr = source.edge_area_mut(..).as_ptr(); + let dest_ptr = dest.edge_area_mut(dest_offset..).as_mut_ptr(); ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr, count); dest.correct_childrens_parent_links(dest_offset..dest_offset + count); } diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 4d05bc4ebfa1e..fd19c0078a748 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -696,8 +696,10 @@ fn test_first_last() { assert_eq!(a.pop_last(), None); } +// Unlike the function with the same name in map/tests, returns no values. +// Which also means it returns different predetermined pseudo-random keys, +// and the test cases using this function explore slightly different trees. fn rand_data(len: usize) -> Vec { - assert!(len <= 70029); // from that point on numbers repeat let mut rng = DeterministicRng::new(); Vec::from_iter((0..len).map(|_| rng.next())) } diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index 6108c139bb3a6..4561c8eaf47fb 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -53,6 +53,9 @@ impl Root { } } + /// Stock up or merge away any underfull nodes on the right border of the + /// tree. The other nodes, those that are not the root nor a rightmost edge, + /// must already have at least MIN_LEN elements. fn fix_right_border(&mut self) { self.fix_top(); @@ -72,6 +75,7 @@ impl Root { } cur_node = last_kv.into_right_child(); } + debug_assert!(cur_node.len() > MIN_LEN); } } @@ -98,6 +102,7 @@ impl Root { } cur_node = first_kv.into_left_child(); } + debug_assert!(cur_node.len() > MIN_LEN); } } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8fd9ff768c4f4..38519f759ae05 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -232,23 +232,27 @@ impl *const T { /// /// # Safety /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). + /// This operation itself is always safe, but using the resulting pointer is not. /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer remains attached to the same allocated object that `self` points to. + /// It may *not* be used to access a different allocated object. Note that in Rust, every + /// (stack-allocated) variable is considered a separate allocated object. /// - /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::())` - /// is *not* the same as `y`, and dereferencing it is undefined behavior - /// unless `x` and `y` point into the same allocated object. + /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` + /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still + /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless + /// `x` and `y` point into the same allocated object. /// - /// Compared to [`offset`], this method basically delays the requirement of staying - /// within the same allocated object: [`offset`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized - /// better and is thus preferable in performance-sensitive code. + /// Compared to [`offset`], this method basically delays the requirement of staying within the + /// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object + /// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a + /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`] + /// can be optimized better and is thus preferable in performance-sensitive code. + /// + /// The delayed check only considers the value of the pointer that was dereferenced, not the + /// intermediate values used during the computation of the final result. For example, + /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other + /// words, leaving the allocated object and then re-entering it later is permitted. /// /// If you need to cross object boundaries, cast the pointer to an integer and /// do the arithmetic there. @@ -571,19 +575,27 @@ impl *const T { /// /// # Safety /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). + /// This operation itself is always safe, but using the resulting pointer is not. + /// + /// The resulting pointer remains attached to the same allocated object that `self` points to. + /// It may *not* be used to access a different allocated object. Note that in Rust, every + /// (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z` + /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still + /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless + /// `x` and `y` point into the same allocated object. /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// Compared to [`add`], this method basically delays the requirement of staying within the + /// same allocated object: [`add`] is immediate Undefined Behavior when crossing object + /// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a + /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`] + /// can be optimized better and is thus preferable in performance-sensitive code. /// - /// Compared to [`add`], this method basically delays the requirement of staying - /// within the same allocated object: [`add`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_add` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized - /// better and is thus preferable in performance-sensitive code. + /// The delayed check only considers the value of the pointer that was dereferenced, not the + /// intermediate values used during the computation of the final result. For example, + /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the + /// allocated object and then re-entering it later is permitted. /// /// If you need to cross object boundaries, cast the pointer to an integer and /// do the arithmetic there. @@ -628,19 +640,27 @@ impl *const T { /// /// # Safety /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). + /// This operation itself is always safe, but using the resulting pointer is not. + /// + /// The resulting pointer remains attached to the same allocated object that `self` points to. + /// It may *not* be used to access a different allocated object. Note that in Rust, every + /// (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z` + /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still + /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless + /// `x` and `y` point into the same allocated object. /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// Compared to [`sub`], this method basically delays the requirement of staying within the + /// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object + /// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a + /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`] + /// can be optimized better and is thus preferable in performance-sensitive code. /// - /// Compared to [`sub`], this method basically delays the requirement of staying - /// within the same allocated object: [`sub`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized - /// better and is thus preferable in performance-sensitive code. + /// The delayed check only considers the value of the pointer that was dereferenced, not the + /// intermediate values used during the computation of the final result. For example, + /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the + /// allocated object and then re-entering it later is permitted. /// /// If you need to cross object boundaries, cast the pointer to an integer and /// do the arithmetic there. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 5f94c2393aef3..92f4e431de499 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -238,23 +238,27 @@ impl *mut T { /// /// # Safety /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). + /// This operation itself is always safe, but using the resulting pointer is not. /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer remains attached to the same allocated object that `self` points to. + /// It may *not* be used to access a different allocated object. Note that in Rust, every + /// (stack-allocated) variable is considered a separate allocated object. /// - /// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::())` - /// is *not* the same as `y`, and dereferencing it is undefined behavior - /// unless `x` and `y` point into the same allocated object. + /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` + /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still + /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless + /// `x` and `y` point into the same allocated object. /// - /// Compared to [`offset`], this method basically delays the requirement of staying - /// within the same allocated object: [`offset`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_offset` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized - /// better and is thus preferable in performance-sensitive code. + /// Compared to [`offset`], this method basically delays the requirement of staying within the + /// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object + /// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a + /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`] + /// can be optimized better and is thus preferable in performance-sensitive code. + /// + /// The delayed check only considers the value of the pointer that was dereferenced, not the + /// intermediate values used during the computation of the final result. For example, + /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other + /// words, leaving the allocated object and then re-entering it later is permitted. /// /// If you need to cross object boundaries, cast the pointer to an integer and /// do the arithmetic there. @@ -678,19 +682,27 @@ impl *mut T { /// /// # Safety /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). + /// This operation itself is always safe, but using the resulting pointer is not. + /// + /// The resulting pointer remains attached to the same allocated object that `self` points to. + /// It may *not* be used to access a different allocated object. Note that in Rust, every + /// (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z` + /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still + /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless + /// `x` and `y` point into the same allocated object. /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// Compared to [`add`], this method basically delays the requirement of staying within the + /// same allocated object: [`add`] is immediate Undefined Behavior when crossing object + /// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a + /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`] + /// can be optimized better and is thus preferable in performance-sensitive code. /// - /// Compared to [`add`], this method basically delays the requirement of staying - /// within the same allocated object: [`add`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_add` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized - /// better and is thus preferable in performance-sensitive code. + /// The delayed check only considers the value of the pointer that was dereferenced, not the + /// intermediate values used during the computation of the final result. For example, + /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the + /// allocated object and then re-entering it later is permitted. /// /// If you need to cross object boundaries, cast the pointer to an integer and /// do the arithmetic there. @@ -735,19 +747,27 @@ impl *mut T { /// /// # Safety /// - /// The resulting pointer does not need to be in bounds, but it is - /// potentially hazardous to dereference (which requires `unsafe`). + /// This operation itself is always safe, but using the resulting pointer is not. + /// + /// The resulting pointer remains attached to the same allocated object that `self` points to. + /// It may *not* be used to access a different allocated object. Note that in Rust, every + /// (stack-allocated) variable is considered a separate allocated object. + /// + /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z` + /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still + /// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless + /// `x` and `y` point into the same allocated object. /// - /// In particular, the resulting pointer remains attached to the same allocated - /// object that `self` points to. It may *not* be used to access a - /// different allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// Compared to [`sub`], this method basically delays the requirement of staying within the + /// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object + /// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a + /// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`] + /// can be optimized better and is thus preferable in performance-sensitive code. /// - /// Compared to [`sub`], this method basically delays the requirement of staying - /// within the same allocated object: [`sub`] is immediate Undefined Behavior when - /// crossing object boundaries; `wrapping_sub` produces a pointer but still leads - /// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized - /// better and is thus preferable in performance-sensitive code. + /// The delayed check only considers the value of the pointer that was dereferenced, not the + /// intermediate values used during the computation of the final result. For example, + /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the + /// allocated object and then re-entering it later is permitted. /// /// If you need to cross object boundaries, cast the pointer to an integer and /// do the arithmetic there. diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 30a8229036fd8..2d60bb0a4bde2 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -500,18 +500,17 @@ impl Step for Rustc { let target = self.target; builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); - // This is the intended out directory for compiler documentation. - let out = builder.compiler_doc_out(target); - t!(fs::create_dir_all(&out)); - - let compiler = builder.compiler(stage, builder.config.build); - if !builder.config.compiler_docs { builder.info("\tskipping - compiler/librustdoc docs disabled"); return; } + // This is the intended out directory for compiler documentation. + let out = builder.compiler_doc_out(target); + t!(fs::create_dir_all(&out)); + // Build rustc. + let compiler = builder.compiler(stage, builder.config.build); builder.ensure(compile::Rustc { compiler, target }); // This uses a shared directory so that librustdoc documentation gets @@ -521,6 +520,10 @@ impl Step for Rustc { // merging the search index, or generating local (relative) links. let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc"); t!(symlink_dir_force(&builder.config, &out, &out_dir)); + // Cargo puts proc macros in `target/doc` even if you pass `--target` + // explicitly (https://github.com/rust-lang/cargo/issues/7677). + let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc"); + t!(symlink_dir_force(&builder.config, &out, &proc_macro_out_dir)); // Build cargo command. let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc"); diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml index 8adc05c513720..21d127c39c904 100644 --- a/src/doc/rustc/book.toml +++ b/src/doc/rustc/book.toml @@ -3,3 +3,6 @@ authors = ["The Rust Project Developers"] multilingual = false src = "src" title = "The rustc book" + +[output.html] +git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc" diff --git a/src/doc/rustdoc/book.toml b/src/doc/rustdoc/book.toml index ba30c107667ed..c2e7ff589066b 100644 --- a/src/doc/rustdoc/book.toml +++ b/src/doc/rustdoc/book.toml @@ -2,3 +2,6 @@ authors = ["The Rust Project Developers"] src = "src" title = "The rustdoc book" + +[output.html] +git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc" diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index 1f6dced180b96..32dc1e02bb3db 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -10,7 +10,7 @@ CSS, and JavaScript. Let's give it a try! Create a new project with Cargo: ```bash -$ cargo new docs +$ cargo new docs --lib $ cd docs ``` diff --git a/src/test/ui/const-generics/issues/issue-80375.rs b/src/test/ui/const-generics/issues/issue-80375.rs new file mode 100644 index 0000000000000..c906bb2c4d9b4 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-80375.rs @@ -0,0 +1,4 @@ +struct MyArray([u8; COUNT + 1]); +//~^ ERROR generic parameters may not be used in const operations + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-80375.stderr b/src/test/ui/const-generics/issues/issue-80375.stderr new file mode 100644 index 0000000000000..9765a639a48d0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-80375.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/issue-80375.rs:1:41 + | +LL | struct MyArray([u8; COUNT + 1]); + | ^^^^^ cannot perform const operation using `COUNT` + | + = help: const parameters may only be used as standalone arguments, i.e. `COUNT` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions + +error: aborting due to previous error + diff --git a/src/test/ui/fn/issue-80179.rs b/src/test/ui/fn/issue-80179.rs new file mode 100644 index 0000000000000..7609b1525cc90 --- /dev/null +++ b/src/test/ui/fn/issue-80179.rs @@ -0,0 +1,27 @@ +// Functions with a type placeholder `_` as the return type should +// show a function pointer suggestion when given a function item +// and suggest how to return closures correctly from a function. +// This is a regression test of #80179 + +fn returns_i32() -> i32 { + 0 +} + +fn returns_fn_ptr() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +//~| NOTE not allowed in type signatures +//~| HELP replace with the correct return type +//~| SUGGESTION fn() -> i32 + returns_i32 +} + +fn returns_closure() -> _ { +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +//~| NOTE not allowed in type signatures +//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound +//~| NOTE for more information on `Fn` traits and closure types, see +// https://doc.rust-lang.org/book/ch13-01-closures.html + || 0 +} + +fn main() {} diff --git a/src/test/ui/fn/issue-80179.stderr b/src/test/ui/fn/issue-80179.stderr new file mode 100644 index 0000000000000..63571e71b34f4 --- /dev/null +++ b/src/test/ui/fn/issue-80179.stderr @@ -0,0 +1,21 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80179.rs:10:24 + | +LL | fn returns_fn_ptr() -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `fn() -> i32` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80179.rs:18:25 + | +LL | fn returns_closure() -> _ { + | ^ not allowed in type signatures + | + = help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound + = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0121`.